skip to Main Content

I have a react app built using nextjs and next-auth and used keycloak running in docker container for identity and access management. Everything works fine if I run the nextjs app outside container with keycloak running inside the container. But when I run the app using docker compose along with keycloak, I get the following error.

[next-auth][error][SIGNIN_OAUTH_ERROR]

https://next-auth.js.org/errors#signin_oauth_error connect ECONNREFUSED 127.0.0.1:8092 {
  error: {
    message: 'connect ECONNREFUSED 127.0.0.1:8092',
    stack: 'Error: connect ECONNREFUSED 127.0.0.1:8092n' +
      '    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1606:16)n' +
      '    at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17)',
    name: 'Error'
  },
  providerId: 'keycloak',
  message: 'connect ECONNREFUSED 127.0.0.1:8092'
}

Here is my compose file.

services:
  romford-web:
    image: myrepo:romoford-web-1.0
    restart: always
    container_name: romford-web
    environment:
      NEXT_PUBLIC_CUSTOMER_API_BASE_URL: http://romford-api:4010/api
      NEXT_PUBLIC_DEFAULT_PAGE_SIZE: 4
      NEXT_PUBLIC_DEFAULT_PAGE_NUMBER: 1
      NEXTAUTH_SECRET: secret
      NEXTAUTH_URL: http://localhost:3000
      NEXTAUTH_URL_INTERNAL: http://romford-web:3000
      KEYCLOAK_CLIENT_ID: next-auth-client
      KEYCLOAK_CLIENT_SECRET: secret-from-keycloack
      KEYCLOAK_ISSUER: http://host.docker.internal:8092/realms/romfordmotors
    ports:
      - '3000:3000'
    networks:
      - my_net

  romford-api:
    image: myrepo:romoford-api-1.0
    restart: always
    container_name: romford-api
    ports:
      - '4010:4010'
    networks:
      - my_net

  postgresql:
    image: postgres
    container_name: postgresql-dev
    restart: unless-stopped
    environment:
      POSTGRES_DB: bitnami_keycloak
      POSTGRES_USER: bn_keycloak
      POSTGRES_PASSWORD: password
      # - ALLOW_EMPTY_PASSWORD=yes
      # - POSTGRESQL_USERNAME=bn_keycloak
      # - POSTGRESQL_DATABASE=bitnami_keycloak
    volumes:
      - 'postgresql_data:/var/lib/postgresql/data'
    networks:
      - my_net

  keycloak:
    image: docker.io/bitnami/keycloak:latest
    container_name: keycloak-dev
    restart: unless-stopped
    ports:
      - '8092:8080'
    environment:
      KEYCLOAK_CREATE_ADMIN_USER: true
      KEYCLOAK_DATABASE_PASSWORD: password
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: admin-password

    depends_on:
      - postgresql
    volumes:
      - 'keycloak_data:/opt/jboss/keycloak/standalone/data'
      - 'keycloak_config:/opt/jboss/keycloak/standalone/configuration'
      # - './mynewtheme:/opt/bitnami/keycloak/themes/mynewtheme'
    networks:
      - my_net

  mongodb:
    image: mongo
    restart: always
    container_name: mongodb
    # environment:
    #   MONGO_INITDB_ROOT_USERNAME: root
    #   MONGO_INITDB_ROOT_PASSWORD: example
    ports:
      - '27018:27017'
    networks:
      - my_net
    volumes:
      - api-data:/data/db

volumes:
  keycloak_data:
  keycloak_config:
  api-data:
  postgresql_data:
    driver: local

networks:
  my_net:
    name: my_net
    # external: true

and providers settings inside my nextjs app are

import NextAuth, { Account, AuthOptions, Session, User } from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import KeycloakProvider, {
  KeycloakProfile,
} from 'next-auth/providers/keycloak';

import bcrypt from 'bcrypt';
import { OAuthConfig } from 'next-auth/providers/oauth';
import { JWT } from 'next-auth/jwt';

export const authOptions = {
  // Configure one or more authentication providers
  providers: [
    // logout will not logout from keycloak idp, so we need to the things as described here
    // https://stackoverflow.com/questions/71872587/logout-from-next-auth-with-keycloak-provider-not-works
    // https://stackoverflow.com/questions/74168539/next-auth-provide-types-for-callback-functions-parameters
    // these are implemented below in events and jwt call backs
    KeycloakProvider({
      clientId: process.env.KEYCLOAK_CLIENT_ID as string,
      clientSecret: process.env.KEYCLOAK_CLIENT_SECRET as string,
      issuer: process.env.KEYCLOAK_ISSUER,
      name: 'Romford motors',
    }),
    CredentialsProvider({
      // The name to display on the sign in form (e.g. "Sign in with...")
      name: 'Credentials',
      // `credentials` is used to generate a form on the sign in page.
      // You can specify which fields should be submitted, by adding keys to the `credentials` object.
      // e.g. domain, username, password, 2FA token, etc.
      // You can pass any HTML attribute to the <input> tag through the object.
      credentials: {
        username: { label: 'Username', type: 'text', placeholder: 'jsmith' },
        password: { label: 'Password', type: 'password' },
      },
      async authorize(credentials, req) {
        // Add logic here to look up the user from the credentials supplied
        const userName = credentials?.username ?? '';
        const password = credentials?.password ?? '';
        // var passwordToEncrypt = '';
        // var hash = await bcrypt.hash(passwordToEncrypt, 10);
        const hash =
          '$2b$10$irGbj/bzy3bgDrfjw4adfQQOMke6tt1uiTf/D34BLeA2Lw7T7wMvADezzC';

        var compareResult = await bcrypt.compare(password, hash);
        const success = userName.toLowerCase() === 'sajid' && compareResult;

        const user = {
          id: '1',
          name: 'Saj Raj',
          email: '[email protected]',
          userName,
        };

        if (success) {
          // Any object returned will be saved in `user` property of the JWT
          return user;
        } else {
          // If you return null then an error will be displayed advising the user to check their details.
          return null;

          // You can also Reject this callback with an Error thus the user will be sent to the error page with the error message as a query parameter
        }
      },
    }),

    // GithubProvider({
    //   clientId: process.env.GITHUB_ID as string,
    //   clientSecret: process.env.GITHUB_SECRET as string,
    // }),
    // ...add more providers here
  ],
  // https://stackoverflow.com/questions/71872587/logout-from-next-auth-with-keycloak-provider-not-works
  // https://stackoverflow.com/questions/74168539/next-auth-provide-types-for-callback-functions-parameters
  callbacks: {
    async jwt({ token, account }: { token: JWT; account: Account | null }) {
      if (account) {
        token.id_token = account.id_token;
        token.provider = account.provider;
        token.access_token = account.access_token;
      }
      return token;
    },
    async session({
      session,
      token,
      user,
    }: {
      session: Session;
      token: JWT;
      user: User;
    }): Promise<Session> {
      session.accessToken = token.access_token;
      session.idToken = token.id_token;
      console.log(session);
      return session;
    },
  },
  events: {
    async signOut(message: { session: Session; token: JWT }) {
      if (message.token.provider === 'keycloak') {
        const issuerUrl = (
          authOptions.providers.find(
            (p) => p.id === 'keycloak'
          ) as OAuthConfig<KeycloakProfile>
        ).options!.issuer!;
        const logOutUrl = new URL(
          `${issuerUrl}/protocol/openid-connect/logout`
        );
        logOutUrl.searchParams.set('id_token_hint', message.token.id_token!);
        await fetch(logOutUrl);
      }
    },
  },
};

export default NextAuth(authOptions);

I have already defined NEXT_AUTH_URL and NEXT_AUTH_SECRET as some answers specified but it is still not working.

2

Answers


  1. Chosen as BEST ANSWER

    I was running docker compose in linux environment and host.docker.internal does not work automatically as in windows. I have to add the following in the nextapp service section of my compose file

    extra_hosts:
      - 'host.docker.internal:host-gateway'  
    

    After adding extrahost, it works fine.


  2. Try to use the service names instead of host.docker.internal.

        KEYCLOAK_ISSUER: http://keycloak:8092/realms/romfordmotors
    

    Change localhost to 0.0.0.0 too.

        NEXTAUTH_URL: http://0.0.0.0:3000
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search