Search code examples
reactjsnext.jssingle-sign-onkeycloaknext-auth

Logout from next-auth with keycloak provider not works


I have a nextjs application with next-auth to manage the authentication.

Here my configuration

....
export default NextAuth({
  // Configure one or more authentication providers
  providers: [
    KeycloakProvider({
      id: 'my-keycloack-2',
      name: 'my-keycloack-2',
      clientId: process.env.NEXTAUTH_CLIENT_ID,
      clientSecret: process.env.NEXTAUTH_CLIENT_SECRET,
      issuer: process.env.NEXTAUTH_CLIENT_ISSUER,
      profile: (profile) => ({
        ...profile,
        id: profile.sub
      })
    })
  ],
....

Authentication works as expected, but when i try to logout using the next-auth signOut function it doesn't works. Next-auth session is destroyed but keycloak mantain his session.


Solution

  • After some research i found a reddit conversation https://www.reddit.com/r/nextjs/comments/redv1r/nextauth_signout_does_not_end_keycloak_session/ that describe the same problem.

    Here my solution.

    I write a custom function to logout

      const logout = async (): Promise<void> => {
        const {
          data: { path }
        } = await axios.get('/api/auth/logout');
        await signOut({ redirect: false });
        window.location.href = path;
      };
    

    And i define an api path to obtain the path to destroy the session on keycloak /api/auth/logout

    export default (req, res) => {
      const path = `${process.env.NEXTAUTH_CLIENT_ISSUER}/protocol/openid-connect/logout? 
                    redirect_uri=${encodeURIComponent(process.env.NEXTAUTH_URL)}`;
    
      res.status(200).json({ path });
    };
    

    UPDATE

    In the latest versions of keycloak (at time of this post update is 19.*.* -> https://github.com/keycloak/keycloak-documentation/blob/main/securing_apps/topics/oidc/java/logout.adoc) the redirect uri becomes a bit more complex

    export default (req, res) => {
    
      const session = await getSession({ req });
    
      let path = `${process.env.NEXTAUTH_CLIENT_ISSUER}/protocol/openid-connect/logout? 
                    post_logout_redirect_uri=${encodeURIComponent(process.env.NEXTAUTH_URL)}`;
    
    if(session?.id_token) {
      path = path + `&id_token_hint=${session.id_token}`
    } else {
      path = path + `&client_id=${process.env.NEXTAUTH_CLIENT_ID}`
    }
    
      res.status(200).json({ path });
    };
    

    Note that you need to include either the client_id or id_token_hint parameter in case that post_logout_redirect_uri is included.