> ## 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 Authorization Code Flow with Fabrixly-IDS
- URL: https://blog.fabrixly.com/how-to-use-authorization-code-flow-3/
- Published: 2026-07-07T14:10:45.000Z
- Updated: 2026-07-07T14:38:40.000Z
- Author: Fabrixly
- Tags: Documentation

## Overview

The Authorization Code Flow is the most secure and recommended flow for web applications with a backend. It exchanges an authorization code for tokens, keeping the client secret secure.

## Prerequisites

1. Fabrixly-IDS instance running
2. OIDC client registered in Fabrixly-IDS
3. Node.js (for example code)

## Step 1: Register Your OIDC Client

First, create a client in Fabrixly-IDS via the Admin Console:

1. Go to **Clients** \> **Create Client**
2. Save the client and note down the `client_id` and `client_secret`

Fill in these details:

```json
{
  "client_name": "My Web App",
  "redirect_uris": ["http://localhost:3001/callback"],
  "response_types": ["code"],
  "grant_types": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_method": "client_secret_basic",
  "auth_mode": "flexible",
  "enable_mobile_login": false,
  "otp_delivery_method": "email",
  "requires_consent": false
}

```

## Step 2: Configure Your App

Install dependencies:

```bash
npm install openid-client express express-session

```

Create `app.js`:

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

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

app.use(session({
  secret: 'your-session-secret-keep-it-safe',
  resave: false,
  saveUninitialized: true
}));

// Step 3: Discover the Fabrixly-IDS Issuer
async function initClient() {
  const issuer = await Issuer.discover('https://ids.fabrixly.com/oidc');
  return new issuer.Client({
    client_id: 'your-client-id',
    client_secret: 'your-client-secret',
    redirect_uris: ['http://localhost:3001/callback'],
    response_types: ['code']
  });
}

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

// Step 4: Redirect to Fabrixly-IDS for Login
app.get('/login', async (req, res) => {
  const codeVerifier = generators.codeVerifier();
  const codeChallenge = generators.codeChallenge(codeVerifier);
  
  // Store verifier in session
  req.session.codeVerifier = codeVerifier;
  req.session.state = generators.state();
  req.session.nonce = generators.nonce();
  
  const authUrl = client.authorizationUrl({
    scope: 'openid profile email offline_access',
    code_challenge: codeChallenge,
    code_challenge_method: 'S256',
    state: req.session.state,
    nonce: req.session.nonce
  });
  
  res.redirect(authUrl);
});

// Step 5: Handle Callback and Exchange Code for Tokens
app.get('/callback', async (req, res) => {
  const params = client.callbackParams(req);
  
  const tokenSet = await client.callback(
    'http://localhost:3001/callback',
    params,
    {
      code_verifier: req.session.codeVerifier,
      state: req.session.state,
      nonce: req.session.nonce
    }
  );
  
  // Store tokens in session
  req.session.tokenSet = tokenSet;
  
  // Get user info
  const userInfo = await client.userinfo(tokenSet.access_token);
  req.session.user = userInfo;
  
  res.redirect('/dashboard');
});

// Step 6: Protected Route Using Access Token
app.get('/dashboard', (req, res) => {
  if (!req.session.user) return res.redirect('/login');
  
  res.send(`
    <h1>Welcome, ${req.session.user.name}</h1>
    <p>Email: ${req.session.user.email}</p>
    <a href="/logout">Logout</a>
  `);
});

// Step 7: Logout
app.get('/logout', async (req, res) => {
  if (req.session.tokenSet) {
    try {
      // Revoke tokens
      if (req.session.tokenSet.access_token) {
        await client.revoke(req.session.tokenSet.access_token);
      }
      if (req.session.tokenSet.refresh_token) {
        await client.revoke(req.session.tokenSet.refresh_token);
      }
    } catch (err) {
      console.error('Error revoking tokens:', err);
    }
  }
  
  req.session.destroy();
  res.redirect('/');
});

app.listen(PORT, () => {
  console.log(`App running on http://localhost:${PORT}`);
});

```

## Step 8: Run the App

```bash
node app.js

```

Visit [http://localhost:3001/login](http://localhost:3001/login?ref=blog.fabrixly.com) to test!

## Using PKCE for Public Clients

For mobile or single-page apps (SPA), use PKCE (Proof Key for Code Exchange) which doesn't require a client secret:

```javascript
// Configure client without client_secret
const client = new issuer.Client({
  client_id: 'your-public-client-id',
  redirect_uris: ['http://localhost:3001/callback'],
  response_types: ['code'],
  token_endpoint_auth_method: 'none'
});

// Use PKCE code verifier and challenge
// Same as Step 4

```

## Token Refresh

Use refresh tokens to get new access tokens without user interaction:

```javascript
// In your app, check if token is expired
if (req.session.tokenSet.expired()) {
  const newTokenSet = await client.refresh(req.session.tokenSet.refresh_token);
  req.session.tokenSet = newTokenSet;
}

```

## API Reference

- **Discovery URL**: `https://ids.fabrixly.com/oidc/.well-known/openid-configuration`
- **Authorization Endpoint**: `/oidc/auth`
- **Token Endpoint**: `/oidc/token`
- **UserInfo Endpoint**: `/oidc/me`
- **Token Introspection**: `/oidc/token/introspection`
- **Token Revocation**: `/oidc/token/revocation`
- **End Session**: `/oidc/session/end`

## Best Practices

1. Always use HTTPS in production
2. Store refresh tokens securely
3. Rotate refresh tokens (enabled by default in Fabrixly-IDS)
4. Validate `state` and `nonce` to prevent CSRF
5. Use short-lived access tokens