NestJS nest-keycloak-connect 401 Unauthorized

Viewed 1154

I am struggling to get anything other than 401 unauthorized when trying to use the nest-keycloak-connect module.

Here is my code.

main.ts

...
import { APP_GUARD } from '@nestjs/core'
import {
  KeycloakConnectModule,
  ResourceGuard,
  RoleGuard,
  AuthGuard
} from 'nest-keycloak-connect';

@Module({
  imports: [TypeOrmModule.forRoot(config), 
    ...
    KeycloakConnectModule.register({
      authServerUrl: 'https://example.com:10443/auth',
      realm: 'sandpit',
      clientId: 'bn_project_manager',
      secret: '314055b4-882a-4c96-87fa-44e9fdea0f5d',
      // optional if you want to retrieve JWT from cookie
      // cookieKey: 'KEYCLOAK_JWT', 
      // optional loglevels. default is verbose
      logLevels: ['verbose'],
      // optional useNestLogger, uses the logger from app.useLogger() implementation
      useNestLogger: false
    }),
  ],
  controllers: [AppController],
  providers: [
    AppService,
    {
      provide: APP_GUARD,
      useClass: AuthGuard,
    },
    {
      provide: APP_GUARD,
      useClass: ResourceGuard,
    },
    {
      provide: APP_GUARD,
      useClass: RoleGuard,
    }
  ],
})
export class AppModule {}

bn.controller.ts

@Controller('bn')
@ApiTags('Business Needs')
@UsePipes(new ValidationPipe())
@Resource('bn_project_manager')
export class BnController {
  constructor(private readonly bnService: BnService) {}

  @Post()
  @Roles({roles: [ 'bn_manage'] })
  @ApiOkResponse({type: Bn})
  create(@Body() createEstimateLineDto: CreateBnDto) {
    return this.bnService.create(createEstimateLineDto);
  }

  @Get()
  @Roles({roles: ['read'] })
  @ApiOkResponse({type: [Bn]})
  findAll() {
    return this.bnService.findAll();
  }
}

I have both the roles setup against my client in keycloak and assigned to the user I am using for testing.

Here is the request I am making to the API endpoint.

curl --location --request POST 'http://localhost:3000/bn' \
--header 'Authorization: Bearer xxxxxxxxxxxxxxx' \
--header 'Content-Type: application/json' \
--data-raw '{
  "bn": "BN1234",
  "projectName": "string"
}'

I don't want to share the JWT token, but here is the relevant content

"realm_access": {
    "roles": [
      "offline_access",
      "uma_authorization"
    ]
  },
  "resource_access": {
    "bn_project_manager": {
      "roles": [
        "bn_manage"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }

Here is the response I get from the API in Postman.

{
    "statusCode": 401,
    "message": "Unauthorized"
}

and here is the verbose logging I get in the nestjs app console.

[Nest] 23972  - 14/07/2021, 14:00:26 VERBOSE [Keycloak] User JWT: xxxxxxxxxxxxxxxxxxxxxxxx
[Nest] 23972  - 14/07/2021, 14:00:26 VERBOSE [Keycloak] undefined
[Nest] 23972  - 14/07/2021, 14:00:26 VERBOSE [Keycloak] Using token validation method: ONLINE
[Nest] 23972  - 14/07/2021, 14:00:26 VERBOSE [Keycloak] undefined

Is there something I need to do that is not documented in the npm README at https://www.npmjs.com/package/nest-keycloak-connnect

1 Answers

I resolved the issue. My Keycloak client had Access Type set to public. I was providing a secret in my config, because TypeScript would not accept the object without a secret key. I assumed that this would be OK, but it turns out that you have to configure your Keycloak client with Access Type = Confidential for this module to work.

Related