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":"x@y.z","given_name":"","family_name":"","email":"x@y.z"}
[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 needed to add the role to the client, but I've added the role to the realm wrongly.

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

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

    If the role is at the client level:

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