Search code examples
reactjsnext.jskeycloakmulti-tenantnext-auth

How to add multi-tenancy using Next Auth and Keycloak provider


I've been trying to use next-auth and keycloak together, but I'm falling when using multi-realms login, using a single keycloak provider I couldn't change clientSecret and issuer options at runtime, so I tried to add multiples keycloak providers with a different id per realm, it works and I can use the react hook to select the right realm:

[...nextauth].ts

const realms = [
    {
        id: 'abc',
        clientId: 'nextjs',
        clientSecret: 'asfasdfdfasdfdasfasfddsf',
        issuer: 'http://localhost:8080/realms/abc',
    },
    {
        id: 'xyz',
        clientId: 'nextjs',
        clientSecret: 'ssdfsdfsdfasdfasdfasdfasfdsdf',
        issuer: 'http://localhost:8080/realms/xyz',
    }
];

providers:

    export default NextAuth({
    providers: realms.map((realm) => KeycloakProvider({
        id: realm.id,
        clientId: realm.clientId,
        clientSecret: realm.clientSecret,
        issuer: realm.issuer
    })),
});

My biggest problem is that I can't include more providers/realms configurations at runtime, it would be nice if I could use an secure end-point to fetch those keycloak configs... so if someone could help me out, showing me some guide how to achieve it, any help is welcome!

My I'm pretty new to NextJS and you can check my full-project-code


Solution

  • Ok I found a solution that seems to work! In the [...nextauth].tsx file, instead of directly exporting the NextAuth function, use a handler just like any other api, and then you can control the providers dynamically. Example:

    export default async function handler(req, res) {
      // getCustomers is a custom function that gets all your customers from the database or wherever
      const customers = await getCustomers() 
      
      // Build a list of all the providers
      const providers = customers.map(customer => KeycloakProvider({
        id: ...
        name: ...
        ...
      }))
    
      // Return the same NextAuth function, but pass the req and res parameters so it can return the response
      return NextAuth(req, res, {
        providers,
        pages: {
          ...
        }    
        ...
      })
    }