How to Use Password + OTP (Two-Factor Authentication, 2FA) with Fabrixly-IDS
Overview
Two-Factor Authentication (2FA) adds an extra layer of security: users enter a password and an OTP to log in! This mode is called password_and_otp in Fabrixly-IDS.
Step 1: Configure 2FA for Your Client
First, set up your client in Fabrixly-IDS to use 2FA:
Admin Console Setup
- Go to Fabrixly-IDS Admin Console → Clients
- Select your client → click Edit
- Under Authentication Settings:
- Auth Mode: select
Password + OTP - Enable Mobile Login: toggle on/off
- OTP Delivery Method: choose email/SMS/both
- Auth Mode: select
- Save!
API Setup
Authenticating API Requests
Management API endpoints (like /api/clients, /api/users, etc.) require administrative authentication. To call them:
- Include the Token in the Authorization Header: Add
-H "Authorization: Bearer <your-admin-jwt-token>"to your API calls.
Obtain an Admin JWT Token:
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.
curl -X POST https://ids.fabrixly.com/api/clients \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-admin-jwt-token>" \
-d '{
"client_name": "2FA App",
"redirect_uris": ["http://localhost:3004/callback"],
"response_types": ["code"],
"grant_types": ["authorization_code", "refresh_token"],
"token_endpoint_auth_method": "client_secret_basic",
"auth_mode": "password_and_otp",
"otp_delivery_method": "email"
}'
User Login Flow
- User visits your app, clicks "Login"
- Redirected to Fabrixly-IDS login screen:
- Step 1: Enter email/mobile number and password → click "Continue"
- Step 2: Receive OTP (via email/SMS) → enter OTP → click "Verify & Log In"
- Fabrixly-IDS validates password and OTP
- User is redirected back to your app with auth code
- App exchanges code for tokens and logs user in!
Example 2FA Express App
Create 2fa-app.js:
const express = require('express');
const session = require('express-session');
const { Issuer, generators } = require('openid-client');
const app = express();
const PORT = 3004;
app.use(session({
secret: '2fa-is-super-secure',
resave: false,
saveUninitialized: true
}));
async function init() {
const issuer = await Issuer.discover('https://ids.fabrixly.com/oidc');
return new issuer.Client({
client_id: 'your-2fa-client-id',
client_secret: 'your-2fa-client-secret',
redirect_uris: ['http://localhost:3004/callback']
});
}
let client;
init().then(c => client = c);
app.get('/', (req, res) => {
if (req.session.user) {
res.redirect('/dashboard');
} else {
res.send(`
<h1>2FA Example App</h1>
<a href="/login">Login with 2FA</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:3004/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>2FA Protected Dashboard!</h1>
<p>Welcome, ${req.session.user.email}!</p>
<p>You logged in with password + OTP 🔐</p>
<a href="/">Home</a>
`);
});
app.listen(PORT, () => console.log(`2FA app running on https://ids.fabrixly.com:${PORT}`));
Why Use 2FA?
- Higher Security: Even if a password is compromised, attackers still need the OTP
- Easy for Users: OTPs are sent to email or SMS, no extra hardware/app needed
- Configurable: Choose delivery methods that work best for your users
Security Best Practices
- Use HTTPS in production!
- Keep OTP expiry short (default: 5 minutes)
- Use short OTP length (6 digits is good)
- Enable account locking after too many failed attempts
- Educate users to not share OTPs!
Troubleshooting
- Password correct but login fails: Check that OTP is still valid and correct
- OTP not arriving: Check spam (email) or verify SMS settings
- Can't switch steps: Ensure
auth_modeis set topassword_and_otpin client config
Next Steps
- Try magic links for even simpler passwordless login!
- Explore social logins!