How to Use Implicit Flow in Fabrixly-IDS
Overview
The Implicit Flow was designed for browser-based single-page apps (SPA) that can't keep a client secret secure. It returns tokens directly from the authorization endpoint.
⚠️ Important: Authorization Code Flow with PKCE is now recommended instead of Implicit Flow for SPAs! But we still support it for legacy apps.
Step 1: Configure Implicit Flow Client
First, set up your OIDC client for implicit flow:
Admin Console Setup
- Go to Fabrixly-IDS Admin Console → Clients
- Create or select client → click Edit
- Under OAuth/OIDC Settings:
- Response Types: add
id_token,token(or both) - Grant Types: add
implicit - Token Endpoint Auth Method: select
none - Auth Mode: choose any auth mode you like
- Response Types: add
- 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": "Implicit Flow SPA",
"redirect_uris": ["http://localhost:3009/callback"],
"response_types": ["id_token", "token"],
"grant_types": ["implicit"],
"token_endpoint_auth_method": "none",
"auth_mode": "flexible"
}'
Step 2: Example Implicit Flow SPA
Create an HTML file implicit-spa.html:
<!DOCTYPE html>
<html>
<head>
<title>Implicit Flow Demo</title>
<style>
.hidden { display: none; }
</style>
</head>
<body>
<h1>Implicit Flow Demo</h1>
<div id="login-section">
<button id="login-btn">Login</button>
</div>
<div id="user-section" class="hidden">
<h2>Hello, <span id="user-name"></span></h2>
<p>Email: <span id="user-email"></span></p>
<p>Access Token: <span id="access-token"></span></p>
<button id="logout-btn">Logout</button>
</div>
<script>
const ISSUER_URL = 'https://ids.fabrixly.com/oidc';
const CLIENT_ID = 'your-implicit-client-id';
const REDIRECT_URI = 'http://localhost:3009/callback';
const SCOPE = 'openid profile email';
// Helper functions
function generateRandomString(length) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
function parseHash(hash) {
const params = {};
const queryString = hash.substring(1);
const regex = /([^&=]+)=([^&]*)/g;
let m;
while (m = regex.exec(queryString)) {
params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
}
return params;
}
// Check for tokens in URL hash when page loads
window.addEventListener('DOMContentLoaded', async () => {
if (window.location.hash) {
const params = parseHash(window.location.hash);
if (params.access_token || params.id_token) {
// Store tokens
sessionStorage.setItem('access_token', params.access_token);
sessionStorage.setItem('id_token', params.id_token);
// Clear hash from URL
window.history.replaceState({}, document.title, window.location.pathname);
// Show user info
await showUserInfo(params.access_token);
}
} else if (sessionStorage.getItem('access_token')) {
await showUserInfo(sessionStorage.getItem('access_token'));
} else {
// Show login button
document.getElementById('login-section').classList.remove('hidden');
}
});
// Login handler
document.getElementById('login-btn').addEventListener('click', () => {
const state = generateRandomString(32);
const nonce = generateRandomString(32);
sessionStorage.setItem('state', state);
sessionStorage.setItem('nonce', nonce);
const authUrl = new URL(`${ISSUER_URL}/auth`);
authUrl.searchParams.set('client_id', CLIENT_ID);
authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
authUrl.searchParams.set('response_type', 'id_token token');
authUrl.searchParams.set('scope', SCOPE);
authUrl.searchParams.set('state', state);
authUrl.searchParams.set('nonce', nonce);
window.location.href = authUrl.toString();
});
// Logout handler
document.getElementById('logout-btn').addEventListener('click', () => {
sessionStorage.clear();
document.getElementById('login-section').classList.remove('hidden');
document.getElementById('user-section').classList.add('hidden');
});
// Fetch user info
async function showUserInfo(accessToken) {
try {
const response = await fetch(`${ISSUER_URL}/me`, {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
const user = await response.json();
document.getElementById('user-name').textContent = user.name;
document.getElementById('user-email').textContent = user.email;
document.getElementById('access-token').textContent = accessToken.substring(0, 20) + '...';
document.getElementById('login-section').classList.add('hidden');
document.getElementById('user-section').classList.remove('hidden');
} catch (err) {
console.error('Error fetching user info:', err);
}
}
</script>
</body>
</html>
Step 3: Serve the SPA
Run a simple HTTP server to serve implicit-spa.html:
npx http-server -p 3009
Visit http://localhost:3009/implicit-spa.html to test!
Implicit Flow Steps
- SPA redirects user to Fabrixly-IDS authorization endpoint
- User logs in (via any auth mode)
- Fabrixly-IDS redirects back to SPA with
id_tokenand/oraccess_tokenin URL hash - SPA parses tokens from hash
- SPA stores tokens in sessionStorage or localStorage
- SPA uses access token to call APIs
Security Considerations
- Use HTTPS always: Tokens are in URL, so HTTPS is critical!
- Short-lived tokens: Implicit flow tokens have short expiry
- Don't store in localStorage: Prefer sessionStorage to limit token lifetime
- Validate state and nonce: Prevents CSRF and replay attacks
- Prefer Authorization Code Flow with PKCE: For new apps, use PKCE instead of implicit!
Troubleshooting
- Tokens not in URL hash: Check client's
response_typesincludesid_tokenand/ortoken - "Invalid redirect_uri": Verify redirect URI matches exactly what's in client config
- CORS errors: Ensure your SPA domain is allowed by Fabrixly-IDS CORS settings
Next Steps
- Try Authorization Code Flow with PKCE instead!
- Add token refresh using silent authentication