CraftDevelopIntegrate

logo
shadow
How to set up Keycloak with NestJS?

How to set up Keycloak with NestJS?

Learn step-by-step instructions on integrating Keycloak authentication with NestJS for robust security and seamless user management.

Syket Bhattachergee
March 4, 20244 min read

Share this article

linkedintwitterfacebookreddit

Looking to enhance your NestJS application's security and user management capabilities? Integrating Keycloak with NestJS can provide a robust solution. Follow this comprehensive guide to effortlessly set up Keycloak authentication within your NestJS application.

What is Keycloak?

Keycloak is a cutting-edge open-source solution for Identity and Access Management tailored for modern applications and services. It simplifies the process of securing applications and services, requiring minimal code intervention. Leveraging open protocol standards such as OpenID Connect and SAML 2.0, Keycloak excels in scenarios like Identity Federation and Single Sign-On (SSO).

Keycloak offers a comprehensive suite of authentication and authorization features, including:

  • Seamless single sign-on and sign-out, with potential integration options for Kerberos (LDAP or Active Directory)

  • Full support for OpenID Connect and SAML 2.0

  • Social media login capabilities

  • User account administration via intuitive web console and REST API

  • Precise, fine-grained authorization controls for diverse service requirements.

How does it work?

Keycloak works by configuring applications to connect to and be protected by its server. When a user interacts with a browser application, they are redirected to the Keycloak authentication server to enter their credentials. This ensures that applications never directly handle user credentials, enhancing security. Instead, applications receive a secure identity token containing information like username, address, and permissions, which allows them to make authorization decisions and access REST-based services securely.

This tutorial assumes some intermediate knowledge. I expect you to know how to create Keycloak realms, and clients, and assign roles to them. In summary, I assume you're familiar with Keycloak. This article will demonstrate how to integrate it with NestJS.

Implementation

  • Add nest Keycloak library to your codebase

      npm install nest-keycloak-connect --save
    
  • Next, we'll incorporate the Keycloak configuration into NestJs. We'll add this configuration to the app.module.ts file. Alternatively, you can create a separate module specifically for Keycloak configuration and then import that module into app.module.ts.

      import { Module } from '@nestjs/common';
      import { AppController } from './app.controller';
      import { AppService } from './app.service';
      import {
        KeycloakConnectModule,
        ResourceGuard,
        RoleGuard,
        AuthGuard,
      } from 'nest-keycloak-connect';
      import { APP_GUARD } from '@nestjs/core';
      @Module({
        imports: [
          KeycloakConnectModule.register({
            authServerUrl: 'http://localhost:8080/auth',
            realm: 'Demo-Realm',
            clientId: 'nest-app',
            secret: '83790b4f-48cd-4b6c-ac60-451a918be4b9',
            // Secret key of the client taken from keycloak server
          }),
        ],
        controllers: [AppController],
        providers: [
          AppService,
          // This adds a global level authentication guard,
          // you can also have it scoped
          // if you like.
          //
          // Will return a 401 unauthorized when it is unable to
          // verify the JWT token or Bearer header is missing.
          {
            provide: APP_GUARD,
            useClass: AuthGuard,
          },
          // This adds a global level resource guard, which is permissive.
          // Only controllers annotated with @Resource and 
          // methods with @Scopes
          // are handled by this guard.
          {
            provide: APP_GUARD,
            useClass: ResourceGuard,
          },
          // New in 1.1.0
          // This adds a global level role guard, which is permissive.
          // Used by `@Roles` decorator with the 
          // optional `@AllowAnyRole` decorator for allowing any
          // specified role passed.
          {
            provide: APP_GUARD,
            useClass: RoleGuard,
          },
        ],
      })
      export class AppModule {}
    
  • Here we are using nest-keycloak-connectAuthGuard, ResourceGuard, and RoleGuard to protect our endpoints.

  • Now we add the following endpoints to our controller and start the application using npm start.

      @Controller()
      export class UserController {
        constructor(private readonly userService: UserService) {}
      @Get()
        getpublic(): string {
          return `${this.userService.getHello()} from public`;
        }
      @Get('/user')
        getUser(): string {
          return `${this.userService.getHello()} from user`;
        }
      @Get('/admin')
        getAdmin(): string {
          return `${this.userService.getHello()} from admin`;
        }
      @Get('/all')
        getAll(): string {
          return `${this.userService.getHello()} from all`;
        }
      }
    
  • You can try to access those endpoints from Postman or a browser. You can see you are getting { “statusCode”: 401, ”message”: ”Unauthorized” } from those endpoints.

  • To give access to those endpoints we can use the following annotations.

      import { Resource, Roles, Scopes, Public, RoleMatchingMode } from 'nest-keycloak-connect';
      import { Controller, Get, Delete, Put, Post, Param } from '@nestjs/common';
    
      @Controller()
      export class UserController {
        constructor(private readonly userService: UserService) {}
      @Get('/public')
        @Unprotected()
        getpublic(): string {
          return `${this.userService.getHello()} from public`;
        }
      @Get('/user')
        @Roles('user')
        getUser(): string {
          return `${this.userService.getHello()} from user`;
        }
      @Get('/admin')
        @Roles('admin')
        getAdmin(): string {
          return `${this.userService.getHello()} from admin`;
        }
      @Get('/all')
        @AllowAnyRole()
        getAll(): string {
          return `${this.userService.getHello()} from all`;
        }
      }
    

Great news! We're nearly finished securing our NestJS app with Keycloak. If you take a look at the controllers, you will see we've utilized the @Roles decorator. Certain routes are accessible to the public, while others require admin privileges. This is how we ensure the security of our routes with Keycloak.

We at CreoWis believe in sharing knowledge publicly to help the developer community grow. Let’s collaborate, ideate, and craft passion to deliver awe-inspiring product experiences to the world.

Let's connect:


This article is crafted by Syket Bhattachergee, a passionate developer at CreoWis. You can reach out to him on X/Twitter, LinkedIn, and follow his work on the GitHub.

CreoWis Technologies © 2024

Crafted with passion by CreoWis