> ## Content Index
> Fetch the complete content index at: https://blog.fabrixly.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# How to Use OTP-Only (Passwordless) Authentication with Fabrixly-IDS
- URL: https://blog.fabrixly.com/how-to-use-otp-only-authentication-3/
- Published: 2026-07-07T14:10:51.000Z
- Updated: 2026-07-07T14:38:50.000Z
- Author: Fabrixly
- Tags: Documentation

## Overview

OTP-only authentication allows users to log in without a password—they just enter their email or mobile number, receive a one-time passcode, and enter it to log in! It's secure and user-friendly.

## Step 1: Configure Your Fabrixly-IDS Client

First, set up your OIDC client in Fabrixly-IDS:

### Admin Console Configuration

1. Open **Fabrixly-IDS Admin Console** → **Clients** → select or create your client
2. Under **Authentication Settings**:
  - **Auth Mode**: select `OTP Only`
  - **Enable Mobile Login**: toggle on/off
  - **OTP Delivery Method**: choose `Email`, `SMS`, or `Both`
3. Save changes!

### API Configuration

### Authenticating API Requests

Management API endpoints (like `/api/clients`, `/api/users`, etc.) require administrative authentication. To call them:

1. **Include the Token in the Authorization Header**: Add `-H "Authorization: Bearer <your-admin-jwt-token>"` to your API calls.

**Obtain an Admin JWT Token**:

```bash
curl -X POST https://ids.fabrixly.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "admin@example.com",
    "password": "your-admin-password"
  }'

```

*Note: This returns a JSON response containing a `token`.*

```bash
curl -X POST https://ids.fabrixly.com/api/clients \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-admin-jwt-token>" \
  -d '{
    "client_name": "Passwordless App",
    "redirect_uris": ["http://localhost:3003/callback"],
    "response_types": ["code"],
    "grant_types": ["authorization_code"],
    "token_endpoint_auth_method": "client_secret_basic",
    "auth_mode": "otp",
    "otp_delivery_method": "email"
  }'

```

## User Login Flow

1. User visits your app and clicks "Login"
2. App redirects to Fabrixly-IDS login page (password field hidden)
3. User enters email or mobile number and clicks "Send OTP"
4. Fabrixly-IDS sends OTP via chosen delivery method(s)
5. User receives OTP, enters it, clicks "Verify & Log In"
6. OTP is validated, user is redirected back to your app with code
7. App exchanges code for tokens and logs user in!

## Example: Express + OTP-Only App

Create `otp-only-app.js`:

```javascript
const express = require('express');
const session = require('express-session');
const { Issuer, generators } = require('openid-client');

const app = express();
const PORT = 3003;

app.use(session({
  secret: 'another-super-secret-key',
  resave: false,
  saveUninitialized: true
}));

async function initClient() {
  const issuer = await Issuer.discover('https://ids.fabrixly.com/oidc');
  return new issuer.Client({
    client_id: 'your-otp-client-id',
    client_secret: 'your-otp-client-secret',
    redirect_uris: ['http://localhost:3003/callback']
  });
}

let client;
initClient().then(c => client = c);

app.get('/', (req, res) => {
  if (req.session.user) {
    res.redirect('/dashboard');
  } else {
    res.send(`
      <h1>Passwordless Login Example</h1>
      <a href="/login">Login with OTP</a>
    `);
  }
});

app.get('/login', (req, res) => {
  req.session.state = generators.state();
  req.session.nonce = generators.nonce();
  
  const authUrl = client.authorizationUrl({
    scope: 'openid profile email',
    state: req.session.state,
    nonce: req.session.nonce
  });
  res.redirect(authUrl);
});

app.get('/callback', async (req, res) => {
  const params = client.callbackParams(req);
  const tokenSet = await client.callback(
    'http://localhost:3003/callback',
    params,
    { state: req.session.state, nonce: req.session.nonce }
  );
  req.session.tokenSet = tokenSet;
  req.session.user = await client.userinfo(tokenSet.access_token);
  res.redirect('/dashboard');
});

app.get('/dashboard', (req, res) => {
  if (!req.session.user) return res.redirect('/');
  
  res.send(`
    <h1>Welcome to Passwordless App!</h1>
    <p>Hello ${req.session.user.email}!</p>
    <p>Logged in without any password! 🎉</p>
    <a href="/">Home</a>
  `);
});

app.listen(PORT, () => console.log(`OTP-only app running on port ${PORT}`));

```

## OTP Delivery Methods

- **Email**: Sends OTP to user's verified email address
- **SMS**: Sends OTP to user's verified mobile number (requires SMS provider set up)
- **Both**: Sends OTP to both email and SMS (user gets both, uses whichever they prefer)

## OTP Settings

You can configure OTP behavior via environment variables (in `.env` file):

```env
OTP_EXPIRY_MINUTES=5  # OTP expires after 5 minutes
OTP_LENGTH=6          # 6-digit OTP

```

## Security Tips

1. **Short Expiry**: Keep OTP expiry short (5‑10 minutes)
2. **Rate Limiting**: Fabrixly-IDS automatically rate-limits OTP requests to prevent abuse
3. **HTTPS**: Always use HTTPS in production
4. **Phone Verification**: Require email/mobile verification before OTP login

## Troubleshooting

- **"No user found" error**: Ensure user exists and has a verified email/mobile number
- **OTP not received**: Check spam folder (for email), or verify SMS provider settings (for SMS)
- **"OTP invalid or expired"**: Request a new OTP

## Next Steps

- Try using "Both" delivery method for redundancy
- Explore flexible authentication
- Enable 2FA for higher-security use cases