Search code examples
nestjskeycloakkeycloak-connectkeycloak-nodejs-connect

keycloak and nodejs (nestjs), wrong role mismatch


I'm using nestjs-keycloak-connect module in multi-tenant mode. The log shows everything is correct but Resource denied due to mismatched role(s). The example controller:

@Controller(':company')
@UseGuards(AuthGuard, RoleGuard)
export class CompanyController {
  @Get('/')
  @Roles({
    roles: ['admin'],
  })
  view(@Param('company') company: string) {
    return `your company is : ${company}`;
  }
}
[Nest] 23435  - 09/08/2022, 11:13:53 PM VERBOSE [Keycloak] Using token validation method: ONLINE
[Nest] 23435  - 09/08/2022, 11:13:53 PM VERBOSE [Keycloak] Authenticated User: {"exp":1662662924,"iat":1662662624,"jti":"13f4b99a-d5bb-4b5f-8fbd-2bffbbcc16ed","iss":"http://localhost:8080/realms/testrealm","aud":"account","sub":"ac10f640-535a-4658-8bcf-daac003e076c","typ":"Bearer","azp":"k","session_state":"66edf11e-e69b-42a9-a1cf-52988d5c9d51","acr":"1","realm_access":{"roles":["default-roles-testrealm","offline_access","admin","uma_authorization"]},"resource_access":{"account":{"roles":["manage-account","manage-account-links","view-profile"]}},"scope":"profile email","sid":"66edf11e-e69b-42a9-a1cf-52988d5c9d51","email_verified":true,"preferred_username":"[email protected]","given_name":"","family_name":"","email":"[email protected]"}
[Nest] 23435  - 09/08/2022, 11:13:53 PM VERBOSE [Keycloak] Controller has no @Resource defined, request allowed due to policy enforcement
[Nest] 23435  - 09/08/2022, 11:13:53 PM VERBOSE [Keycloak] Using matching mode: any
[Nest] 23435  - 09/08/2022, 11:13:53 PM VERBOSE [Keycloak] Roles: ["admin"]
[Nest] 23435  - 09/08/2022, 11:13:53 PM VERBOSE [Keycloak] Resource denied due to mismatched role(s)

I can't understand where is the problem!


Solution

  • I've needed to add the role to the client. I've added the role to the realm.

    In nest js this code will help if the role is at realm level:

      @Get('/admin')
      @Scopes('delete')
      @Roles({ roles: ["realm:admin"] })
      getAdmin(): string {
        return 'admin';
      }
    

    If the role is at client level:

     @Get('/admin')
      @Scopes('delete')
      @Roles({ roles: ["admin"] })
      getAdmin(): string {
        return 'admin';
      }