I am encountering an issue with Keycloak integration in my NestJS application. My environment uses Docker for orchestrating services. Here is an overview of my configuration and relevant files:
Context
Dockerfile:
FROM node:18-alpine WORKDIR /app COPY package.json ./ COPY package-lock.json ./ RUN npm install COPY . . RUN npx prisma generate RUN npm run build EXPOSE 3000 CMD ["node", "dist/main.js"]docker-compose.yml:
version: '3.8' services: nest-app: build: context: . dockerfile: Dockerfile ports: - "3000:3000" environment: DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/mydatabase" depends_on: postgres: condition: service_healthy networks: - my-network postgres: image: postgres:latest environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: mydatabase ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data networks: - my-network healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 10s timeout: 5s retries: 5 keycloak: image: quay.io/keycloak/keycloak:latest environment: DB_VENDOR: h2 KEYCLOAK_ADMIN: admin KEYCLOAK_ADMIN_PASSWORD: admin KEYCLOAK_IMPORT: /tmp/realm.json ports: - "8081:8080" volumes: - ./realm.json:/tmp/realm.json entrypoint: ["/opt/keycloak/bin/kc.sh"] command: ["start-dev"] networks: - my-network volumes: postgres_data: networks: my-network: driver: bridgeapp.module.ts:
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { AuthGuard, KeycloakConnectModule, ResourceGuard, RoleGuard, } from 'nest-keycloak-connect'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { PrismaModule } from './prisma.module'; import { APP_GUARD } from '@nestjs/core'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, }), PrismaModule, KeycloakConnectModule.register({ authServerUrl: 'http://127.0.0.1:8081/', realm: 'test', clientId: 'my-nest-project', secret: 'GSLUjhMMctvip6B01q3g7xu6P8SJBvT6', // or `credentials.secret` if used }), ], controllers: [AppController], providers: [ AppService, { provide: APP_GUARD, useClass: AuthGuard, }, { provide: APP_GUARD, useClass: ResourceGuard, }, { provide: APP_GUARD, useClass: RoleGuard, }, ], }) export class AppModule {}app.service.ts:
import { Injectable } from '@nestjs/common'; @Injectable() export class AppService { getHello(): string { return 'Hello, World!'; } getProtectedMessage(): string { return 'This is a protected route'; } getTestMessage(): string { return 'This is a test route'; } }main.ts:
import { NestFactory } from '@nestjs/core'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { AppModule } from './app.module'; import { PrismaService } from './prisma.service'; async function bootstrap() { const app = await NestFactory.create(AppModule); // Swagger configuration const config = new DocumentBuilder() .setTitle('API Documentation') .setDescription('The API description') .setVersion('1.0') .addBearerAuth() .addTag('app') .addTag('hello') .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api', app, document); const prismaService = app.get(PrismaService); await prismaService.enableShutdownHooks(app); await app.listen(3000); } bootstrap();
Issue
When using Keycloak with my NestJS application, I get the following error in the Keycloak logs:
WARN [Keycloak] Cannot validate access token: Error: Grant validation failed. Reason: invalid token (wrong ISS)
API Calls
Public Endpoints:
- GET
http://localhost:3000/(works correctly) - GET
http://localhost:3000/test(works correctly) - GET
http://localhost:3000/hello(works correctly) - GET
http://localhost:8081/realms/test(works correctly)
- GET
Get Token from Keycloak: (works correctly)
- POST
http://localhost:8081/realms/test/protocol/openid-connect/token
- POST
Access Protected Route with Bearer Token: (fails with 401 Unauthorized)
- GET
http://localhost:3000/protected
- GET
What I Tried
**Valid Token Check: ** I used the Keycloak admin interface to get a token and tried accessing the protected route. Expected: Successful access to the protected route with the valid token. Actual Result: Received a 401 Unauthorized response.
Different authServerUrl Configurations:
I tested various configurations for authServerUrl in app.module.ts:
- http://127.0.0.1:8081/
- http://127.0.0.1:8081/auth
- http://localhost:8081/auth
Expected: Proper token validation and successful access to the protected route. Actual Result: The same 401 Unauthorized response with the wrong ISS error.
Recreating the Keycloak Realm: I attempted to recreate the Keycloak realm to ensure no configuration issues. Expected: Correctly configured realm leading to successful token validation. Actual Result: The issue persists with the same error.
Search on Stack Overflow: I searched for solutions on Stack Overflow using keywords related to this error, but I did not find a satisfactory answer. Expected: To find solutions or clues to resolve the token validation issue. Result: No conclusive answers found.
Questions
- What can I check or adjust to resolve this error?
- Are there additional configurations I should include in my Docker or NestJS setup to ensure proper integration with Keycloak?
issfield in token not same domain withauthServerUrlin server. Just config BE and FE point to same domain keycloak.