How to integrate SSO Keycloak Directus to Front End?

Dear All,
I have a directus that already integrate to SSO Keycloak with this settings:

"AUTH_PROVIDERS": "keycloak",
"AUTH_KEYCLOAK_DRIVER": "openid",
"AUTH_KEYCLOAK_CLIENT_ID": "directus",
"AUTH_KEYCLOAK_CLIENT_SECRET": "secret",
"AUTH_KEYCLOAK_ISSUER_URL": "https://sso.domain.net/realms/realmdomain/.well-known/openid-configuration",
"AUTH_KEYCLOAK_IDENTIFIER_KEY": "email",
"AUTH_KEYCLOAK_ALLOW_PUBLIC_REGISTRATION": true,
"AUTH_KEYCLOAK_REDIRECT_ALLOW_LIST": "http://localhost:3000",
"AUTH_KEYCLOAK_LABEL": "SSO-Domain-ID",
"ACCESS_TOKEN_TTL": "15m",
"REFRESH_TOKEN_TTL": "7d",
"REFRESH_TOKEN_COOKIE_SECURE": false,
"REFRESH_TOKEN_COOKIE_SAME_SITE": "lax",
"REFRESH_TOKEN_COOKIE_NAME": "directus_refresh_token",
"SESSION_COOKIE_TTL": "1d",
"SESSION_COOKIE_SECURE": false,
"SESSION_COOKIE_SAME_SITE": "lax",
"SESSION_COOKIE_NAME": "directus_session_token",

With those settings, users can login to directus admin UI with their SSO credentials. It’s done.

Now, I want to integrate my frontend with SSO keycloak and directus as backend. I tried using same client with directus, but after successful login in SSO Keycloak login page, it redirected back to directus admin site, not frontend site.

I also tried using new client, dedicated for frontend site. So redirect_URI set to http://localhost:3000/api/auth/callback/keycloak and when i click “login with SSO”, it redirected to Keycloak login page as it should be.

This is my /api/auth/callback/keycloak/route.ts (I’m using nextjs 13.5.1):

import { NextRequest } from 'next/server';

export const dynamic = 'force-dynamic';

export async function GET(request: NextRequest) {
  try {
    const { searchParams } = new URL(request.url);
    const code = searchParams.get('code');
    const error = searchParams.get('error');

    if (error) {
      return Response.json({ error }, { status: 400 });
    }
    if (!code) {
      return Response.json({ error: 'Missing authorization code' }, { status: 400 });
    }

    // Exchange code for tokens
    const tokenRes = await fetch('https://sso.domain.net/realms/realmdomain/protocol/openid-connect/token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        client_id: 'portaldev',
        grant_type: 'authorization_code',
        code,
        redirect_uri: 'http://localhost:3000/api/auth/callback/keycloak',
      }),
    });

    if (!tokenRes.ok) {
      const err = await tokenRes.text();
      return Response.json({ error: 'Failed to exchange code for tokens', details: err }, { status: 400 });
    }
    const tokens = await tokenRes.json();

    // Fetch user info
    const userinfoRes = await fetch('https://sso.domain.net/realms/realmdomain/protocol/openid-connect/userinfo', {
      headers: {
        Authorization: `Bearer ${tokens.access_token}`,
      },
    });
    const userinfo = userinfoRes.ok ? await userinfoRes.json() : null;

    // Set cookie for access_token
    const cookie = `kc_access_token=${tokens.access_token}; Path=/; HttpOnly; Secure; Max-Age=${tokens.expires_in}`;
    // Redirect to homepage after SSO
    return new Response(null, {
      status: 302,
      headers: {
        'Set-Cookie': cookie,
        'Location': '/',
      },
    });
  } catch (err) {
    console.error('Keycloak SSO callback error:', err);
    return Response.json({ error: 'Internal server error' }, { status: 500 });
  }
} 

But it stuck, redirected to unauth homepage.

How to do it correctly?

After some test and trials, I’m stuck with this conditions:
Directus: 11.9.2
Keycloak: 26.2.4
Nextjs: 13.5.1

  1. I see that in worked Directus Admin UI, “Login with Keycloak” href to https://directusdomain/auth/login/keycloak?redirect=https://directusdomain/admin/login?=continue
  2. But I want to redirect to frontend again after successful keycloak login. So I tried: https://directusdomain/auth/login/keycloak?redirect=https://localhost:3000 but it failed with this errror: Invalid Payload, https://localhost:3000 can’t be used to redirect after login. But when I change “redirect” to “redirect_url” (https://directusdomain/auth/login/keycloak?redirect_url)=https://localhost:3000) it work, it redirected to sso keycloak login page.
  3. But, after success keycloak login, it stay in this kind of link: https://directusdomain/auth/login/keycloak/callback?state=fV7Td1q9redacted&iss=https%3A%2F%2Fsso.domain.net%2Frealms%2Fdomainrealm&code=34a22080-aredacted with this JSON data shown up in browser:
    {“data”:{“access_token”:“eyA”,“refresh_token”:“bn-V4A”,“expires”:86400000}}
    And I tested the refresh_token via postman to /auth/refresh, it worked!

Any ideas, how to get it done from here?

1 Answer

1

Heya! Apologies for the late answer here..

Directus itself is the thing you want to login to from your Next.js application, rather than Keycloak directly, as Directus doesn’t share a token with Keycloak. In a setup where you login from Next.js directly to Keycloak, you effectively end up with 2 user sessions: one to directus and one to keycloak. Since this was posted, we’ve updated our documentation on configuring this type of SSO flow, so hopefully that sheds about it more light on how you can best implement this nowadays https://directus.io/docs/guides/auth/sso/seamless#implementing-seamless-sso :slight_smile: