Code Monkey home page Code Monkey logo

nest-keycloak-connect's Introduction

Nest Keycloak Connect

GitHub Issues or Pull Requests GitHub License

NPM Version NPM dev or peer Dependency Version NPM dev or peer Dependency Version

GitHub Actions Workflow Status NPM Weekly Downloads NPM Total Downloads

An adapter for keycloak-nodejs-connect

Features

Installation

Yarn

yarn add nest-keycloak-connect keycloak-connect

NPM

npm install nest-keycloak-connect keycloak-connect --save

Getting Started

Module registration

Registering the module:

KeycloakConnectModule.register({
  authServerUrl: 'http://localhost:8080', // might be http://localhost:8080/auth for older keycloak versions
  realm: 'master',
  clientId: 'my-nestjs-app',
  secret: 'secret',
  policyEnforcement: PolicyEnforcementMode.PERMISSIVE, // optional
  tokenValidation: TokenValidation.ONLINE, // optional
});

Async registration is also available:

KeycloakConnectModule.registerAsync({
  useExisting: KeycloakConfigService,
  imports: [ConfigModule],
});

KeycloakConfigService

import { Injectable } from '@nestjs/common';
import {
  KeycloakConnectOptions,
  KeycloakConnectOptionsFactory,
  PolicyEnforcementMode,
  TokenValidation,
} from 'nest-keycloak-connect';

@Injectable()
export class KeycloakConfigService implements KeycloakConnectOptionsFactory {
  createKeycloakConnectOptions(): KeycloakConnectOptions {
    return {
      authServerUrl: 'http://localhost:8080', // might be http://localhost:8080/auth for older keycloak versions
      realm: 'master',
      clientId: 'my-nestjs-app',
      secret: 'secret',
      policyEnforcement: PolicyEnforcementMode.PERMISSIVE,
      tokenValidation: TokenValidation.ONLINE,
    };
  }
}

You can also register by just providing the keycloak.json path and an optional module configuration:

KeycloakConnectModule.register(`./keycloak.json`, {
  policyEnforcement: PolicyEnforcementMode.PERMISSIVE,
  tokenValidation: TokenValidation.ONLINE,
});

Guards

Register any of the guards either globally, or scoped in your controller.

Global registration using APP_GUARD token

NOTE: These are in order, see https://docs.nestjs.com/guards#binding-guards for more information.

providers: [
  {
    provide: APP_GUARD,
    useClass: AuthGuard,
  },
  {
    provide: APP_GUARD,
    useClass: ResourceGuard,
  },
  {
    provide: APP_GUARD,
    useClass: RoleGuard,
  },
];

Scoped registration

@Controller('cats')
@UseGuards(AuthGuard, ResourceGuard)
export class CatsController {}

What does these providers do ?

AuthGuard

Adds an authentication guard, you can also have it scoped if you like (using regular @UseGuards(AuthGuard) in your controllers). By default, it will throw a 401 unauthorized when it is unable to verify the JWT token or Bearer header is missing.

ResourceGuard

Adds a resource guard, which is permissive by default (can be configured see options). Only controllers annotated with @Resource and methods with @Scopes are handled by this guard.

NOTE: This guard is not necessary if you are using role-based authorization exclusively. You can use role guard exclusively for that.

RoleGuard

Adds a role guard, can only be used in conjunction with resource guard when enforcement policy is PERMISSIVE, unless you only use role guard exclusively. Permissive by default. Used by controller methods annotated with @Roles (matching can be configured)

Configuring controllers

In your controllers, simply do:

import {
  Resource,
  Roles,
  Scopes,
  Public,
  RoleMatchingMode,
} from 'nest-keycloak-connect';
import { Controller, Get, Delete, Put, Post, Param } from '@nestjs/common';
import { Product } from './product';
import { ProductService } from './product.service';

@Controller()
@Resource(Product.name)
export class ProductController {
  constructor(private service: ProductService) {}

  @Get()
  @Public()
  async findAll() {
    return await this.service.findAll();
  }

  @Get()
  @Roles({ roles: ['admin', 'other'] })
  async findAllBarcodes() {
    return await this.service.findAllBarcodes();
  }

  @Get(':code')
  @Scopes('View')
  async findByCode(@Param('code') code: string) {
    return await this.service.findByCode(code);
  }

  @Post()
  @Scopes('Create')
  async create(@Body() product: Product) {
    return await this.service.create(product);
  }

  @Delete(':code')
  @Scopes('Delete')
  @Roles({ roles: ['admin', 'realm:sysadmin'], mode: RoleMatchingMode.ALL })
  async deleteByCode(@Param('code') code: string) {
    return await this.service.deleteByCode(code);
  }

  @Put(':code')
  @Scopes('Edit')
  async update(@Param('code') code: string, @Body() product: Product) {
    return await this.service.update(code, product);
  }
}

Decorators

Here is the decorators you can use in your controllers.

Decorator Description
@AuthenticatedUser Retrieves the current Keycloak logged-in user. (must be per method, unless controller is request scoped.)
@EnforcerOptions Keycloak enforcer options.
@Public Allow any user to use the route.
@Resource Keycloak application resource name.
@Scopes Keycloak application scope name.
@Roles Keycloak realm/application roles.

Multi tenant configuration

Setting up for multi-tenant is configured as an option in your configuration:

{
  authServerUrl: 'http://localhost:8180/auth',
  clientId: 'nest-api',
  secret: 'fallback', // will be used as fallback when resolver returns null
  multiTenant: {
    realmResolver: (request) => {
      return request.get('host').split('.')[0];
    },
    realmSecretResolver: (realm, request) => {
      const secrets = { master: 'secret', slave: 'password' };
      return secrets[realm];
    },
    realmAuthServerUrlResolver: (realm, request) => {
      const authServerUrls = { master: 'https://master.local/auth', slave: 'https://slave.local/auth' };
      return authServerUrls[realm];
    }
  }
}

Configuration options

Keycloak Options

For Keycloak options, refer to the official keycloak-connect library.

Nest Keycloak Options

Option Description Required Default
cookieKey Cookie Key no KEYCLOAK_JWT
logLevels Built-in logger level (deprecated, will be removed in 2.0) no log
useNestLogger Use the nest logger (deprecated, will be removed in 2.0) no true
policyEnforcement Sets the policy enforcement mode no PERMISSIVE
tokenValidation Sets the token validation method no ONLINE
multiTenant Sets the options for multi-tenant configuration no -
roleMerge Sets the merge mode for @Role decorator no OVERRIDE

Multi Tenant Options

Option Description Required Default
resolveAlways Option to always resolve the realm and secret. Disabled by default. no false
realmResolver A function that passes a request (from respective platform i.e express or fastify) and returns a string yes -
realmSecretResolver A function that passes the realm string, and an optional request and returns the secret string no -
realmAuthServerUrlResolver A function that passes the realm string, and an optional request and returns the auth server url string no -

Example app

An example application is provided in the source code with both Keycloak Realm and Postman requests for you to experiment with.

nest-keycloak-connect's People

Contributors

abiodunsulaiman694 avatar andreferraro avatar ap-tianjef avatar ayushkamadji avatar codeonetwo avatar d3215k avatar efritzsche90 avatar emaung avatar ferrerojosh avatar formateu avatar jalorenz avatar joravkumar avatar josepaiva94 avatar juergenzimmermann avatar manishkgitrepo avatar marcosvto1 avatar rokal avatar samhoque avatar talbx avatar toilal avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nest-keycloak-connect's Issues

Problem validating token using client_credentials grant

Hello guys,

Thanks for the great module, is really helpful.

I'm using keycloak v12.0.4 and nest-keycloak-connect v1.5.2.

I don't know if i'm doing something wrong, but i'm getting the following message when trying to use an protected route after getting an client_credentials token:

  • [Keycloak] Cannot validate access token: Error: Error fetching account

If i get a password grant, than everything works. I believe the problem is at the auth.guard.ts, at line 81:

request.user = await this.keycloak.grantManager.userInfo(jwt);

At this point, keycloak throws the following exception:

11:42:42,883 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-53) Uncaught server error: java.lang.NullPointerException: Null keys are not supported!
	at java.base/java.util.Objects.requireNonNull(Objects.java:246)

Is it possible that, in client credentials grant, we should not get this userInfo ? Or maybe i'm missing something in the service account configuration ?

Thanks in advance for the help.

Set keycloak-connect as a peerDependency

Hi there, @ferrerojosh! First of all, great job! This library is excellent! I wonder if we could set keycloak-connect as a peerDependency instead of a direct dependency. We are having some trouble with keycloak-connect and we'd like to use our own fork/version. Do you have any thoughts on it?

P.S: Let me know if you need help maintaining nest-keycloak-connect :)

Expose the KEYCLOAK_INSTANCE constant

Hello!

I would like to use the KEYCLOAK_INSTANCE constant so I can inject the Keycloak instance in my application.

Like this:

import { KEYCLOAK_INSTANCE } from 'nest-keycloak-connect';

constructor(@Inject(KEYCLOAK_INSTANCE) private keycloak: KeycloakConnect.Keycloak) {}

Exposing the KEYCLOAK_INSTANCE constant through the library interface is that something you would like to do? If yes, I could make a PR for it.

Cheers

make @Public work with controller class

currently only check routes

const isUnprotected = this.reflector.get<boolean>(
META_UNPROTECTED,
context.getHandler(),
);

this may help https://github.com/nestjs/nest/blob/54570aa0c81ceca447f6c990fe186f41dbdbfda7/packages/core/services/reflector.service.ts#L78-L93

  /**
   * Retrieve metadata for a specified key for a specified set of targets and return a first not undefined value.
   *
   * @param metadataKey lookup key for metadata to retrieve
   * @param targets context (decorated objects) to retrieve metadata from
   *
   */
  public getAllAndOverride<TResult = any, TKey = any>(
    metadataKey: TKey,
    targets: (Type<any> | Function)[],
  ): TResult {
    const metadataCollection = this.getAll(metadataKey, targets).filter(
      item => item !== undefined,
    );
    return metadataCollection[0];
  }

Missing implementation for Resource-Based Authorization

According to the docs enforcer function can also have a claims function to define the resource URI's. Currently, nest-keycloak-connect doesnt provide the functionality.

      ​app.get('/protected/resource', keycloak.enforcer(['resource:view', 'resource:write'], {
         ​claims: function(request) {
           ​return {
             ​"http.uri": ["/protected/resource"],
             ​"user.agent": // get user agent  from request
           ​}
         ​}
       ​}), function (req, res) 

Express support?

You wrote "Compatible with Fastify platform.".
Does it mean, it will not work, when the default Express base is used ?
And if not working on Express base, are you planning to support it in the near future ?

Thanks
Matthias

How to use with Keycloak authorization resources, policies and permissions

How do I use @scopes() with the @resource() decorators to validate that user has the correct permissions and polices assinged.

This might be an issue with my knowledge of Keycloak, or a misunderstanding of how the decorator terminology is used in this library.

I assumed that the combination of @resource() at the controller level with @scopes() at the method level, along with the logged-in user, would allow me to create Resources and Permission in Keycloak and have this library validate them for a given user.

Can someone give me some context by providing an example of adding a Scope and a Resource to the JWT in keycloak and how I would interact with them using @resource() and @scope()

1.7.0 release missing built js files

First, thanks for the work on this project!

I installed release 1.7.0 for Nest 8 support, but the NPM package only has TypeScript files. Looks like the build wasn't packaged, just the source.

Offline JWT validation

Hi,

I'm using this great NestJS module to connect Keycloak to my backend microservice and I've noticed that the Auth guard only applies online JWT validation:

const result = await this.keycloak.grantManager.validateAccessToken(jwt);

If I'm not wrong, the keycloak-connect lib has also a validateToken method able to validate JWT offline, if the publicKey is defined.

Do you plan to add the offline validation in the Auth guard?

Nest not start

Nest app does not start me, and I have it configured exactly as in the documentation, this is the error:
nest

Compatibility with Nest 8

Hi @ferrerojosh, and contributors! Great library!! Congrats

I write you because I'm having troubles to use the library with the new Nest libraries version (8.0.4). This is the error trying to install nest-keycloak-connect on a new Nest project:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: [email protected]
npm ERR! Found: @nestjs/[email protected]
npm ERR! node_modules/@nestjs/common
npm ERR!   @nestjs/common@"^8.0.0" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer @nestjs/common@"^7.0.3" from [email protected]
npm ERR! node_modules/nest-keycloak-connect
npm ERR!   nest-keycloak-connect@"*" from the root project

Is it my fault, or is there a way to solve it?
If not, is there a plan to update nest-keycloak-connect to solve the issue?

Thanks!
Best Regards

TokenValidation example in README does not adhere to comment

Hey, I just read the README's getting started and thought that the tokenValidation in the following snippet (taken from the README) should be TokenValidation.ONLINE.

      // optional, already defaults to online validation
      tokenValidation: TokenValidation.NONE,

Just like the policyEnforcement mode is set to permissive following the comment.

      // optional, already defaults to permissive
      policyEnforcement: PolicyEnforcementMode.PERMISSIVE,

ValidateAccessToken Error: Error: 404:Not Found

I got error when access this end point.

@controller()
@resource('test')
export class AppController {
constructor(private readonly appService: AppService) {
}

@Get('login')
@Roles('master:admin', 'Hello:admin', 'admin')
@AllowAnyRole()
async getHello() {
    return true;
}

validateAccessToken Error: Error: 404:Not Found at ClientRequest.<anonymous> (/Users/HELLO/Documents/GitHub/MY_COM/app-service/node_modules/keycloak-connect/middleware/auth-utils/grant-manager.js:523:23) at Object.onceWrapper (events.js:422:26) at ClientRequest.emit (events.js:315:20) at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:596:27) at HTTPParser.parserOnHeadersComplete (_http_common.js:119:17) at Socket.socketOnData (_http_client.js:469:22) at Socket.emit (events.js:315:20) at addChunk (_stream_readable.js:295:12) at readableAddChunk (_stream_readable.js:271:9) at Socket.Readable.push (_stream_readable.js:212:10) at TCP.onStreamRead (internal/stream_base_commons.js:186:23)

@AllowAnyRole is confusing

As of the moment, @AllowAnyRole decorator is quite confusing. I am planning to deprecate this decorator in favor of a better name. It also confused developers since they are using it alone when @Roles is supposedly be used together with it (yes @AllowAnyRole won't do anything without @Roles).

I can take it any suggestions you like for this.

Empty JWT will result in valid (authenticated) request in version 1.5

When changing from version 1.4.3 to version 1.5 requests with no JWT will still be seen as authenticated requests.

It was probably introduced in the commit 244a109 with the following:
244a109#diff-231e8526045ebda19da204498033feaa52eb8ea104797e7847369fc243f93aa8R62

Example:
Valid JWT
image

Invalid JWT
image

Empty JWT
image

which shows on the server (with loglevel verbose) but still throws no AuthenticationException
image

My module and contorller are basic ones without anything special:
Module

@Module({
  imports: [
    // ...
    KeycloakConnectModule.register({
      authServerUrl: 'myauth.com/auth',
      realm: 'master',
      clientId: 'client_id',
      secret: 'client_secret',
      logLevels: ['verbose']
    }),
  ],
  providers: [
    {
      provide: APP_GUARD,
      useClass: AuthGuard,
    },
  ],
})

Controller

@ApiTags('Resource')
@Controller('resource')
@ApiBearerAuth()
export class ResourceController {
  constructor(private readonly resource: ResourceService) {}

  @Get()
  getAll(): Promise<Resource[]> {
    return this.resource.getAll();
  }
  // ...
}

Because this commit was a bugfix, Im not sure if this is wanted behavior or not.
But all in all I think permitting requests without a valid JWT is pretty problematic.

@Public and @Unprotected decorator cannot be used

Version: 1.3.0
Typescript: 4.1.2

Using @public or @unprotected decorator is not possible. Following error is shown in console.

TS1241: Unable to resolve signature of method decorator when called as an expression.   This expression is not callable. Type 'void' has no call signatures.

If I use "any" instead of "void" it is working.

keycloak 11 & nest-keycloak-connect 1.3.0-alpha.3 - fail to get 200 with roles

Hi,

I'm trying to make this project work with latest keycloak docker instance (currently version 11.x).

Using a fresh nestjs project with latest nest-keycloak-connect i'm using the following code :

@Controller()
@Resource('admin')
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get('admin')
  @Roles('admin')
  getHello(): string {
    return this.appService.getHello();
  }
}

I have setup a keycloak custom realm, with a scope "admin" and a role "admin" under it.
Here is the decoded jwt I try to pass to the app :

{
  "exp": 1598143670,
  "iat": 1598143370,
  "jti": "f5b80827-0573-4710-a548-14ace94d1473",
  "iss": "http://localhost:8080/auth/realms/testproject",
  "sub": "e85763bd-281a-4fca-86a0-f7afcaaf46d2",
  "typ": "Bearer",
  "azp": "admin-cli",
  "session_state": "e7b4e27b-8cba-4124-9d41-c1659ceeec23",
  "acr": "1",
  "realm_access": {
    "roles": [
      "admin"
    ]
  },
  "scope": "email admin roles profile",
  "email_verified": true,
  "name": "admin",
  "preferred_username": "admin",
  "given_name": "admin",
  "family_name": "admin",
  "email": "[email protected]"
}

I also try to add @scopes('admin'), without much more success.

Do I miss something ? Which version of keycloak is supported by this lib ?

Thanks for your help.

@AuthenticatedUser in GraphQL Resolver

Hi, is it possible to access the current user in a GraphQL resolver?

I followed your example project and endpoints are secured; the logs show that there is a user authenticated, using @AuthenticatedUser though breaks the code, since "user" seems not to be present in the req object:

Nest] 3045   - 25.05.2021, 14:14:30   [ExceptionsHandler] Cannot read property 'user' of undefined +1ms
TypeError: Cannot read property 'user' of undefined

Here's the code:

import { Query, Resolver } from '@nestjs/graphql';
import { AuthenticatedUser, Public, Resource } from 'nest-keycloak-connect';
import { User } from './entities/user.entity';

@Resolver(() => User)
export class UsersResolver {
  @Query(() => User)
  @Public(false)
  async currentUser(@AuthenticatedUser() authUser: any) {
    const user = new User();
    user.id = 1;
    user.sub = 'bla';
    user.isVerified = true;
    user.email = '[email protected]';

    return user;
  }
}

keycloak config differ from the one provided by keycloak server

Keycloak nodejs lib allow user to configure the connection using a JSON File (keycloak.json) or in copy paste from the admin console. https://www.keycloak.org/docs/latest/securing_apps/#usage-2

Here is the source code for this.
https://github.com/keycloak/keycloak-nodejs-connect/blob/f8e011aea5/middleware/auth-utils/config.js

Can we align the https://github.com/ferrerojosh/nest-keycloak-connect/blob/master/src/interface/keycloak-connect-options.interface.ts to reflect the same structure ?

Logging

Hi,

any chance to see some verbose logging in the future?
Preferable using nest logging and as option in KeycloakConnectOptions.

KeycloakConnectModule.register({ ..., logLevel: 'debug' })

and 'warn' or 'error' as default.

Kind regards,
Michael

AuthenticatedUser decorator

I'm developing a multi-tenant app and I trying to extract keycloak user attribute using AuthenticatedUser decorator. I didn't receive custom attributes that define with one tanant is ablet to user access, I miss some configutarion? I already tryed put on Keycloak mapper, no success.

Load dynamic configuration is not working

I am facing this error

Nest can't resolve dependencies of the KEYCLOAK_LOGGER (?). Please make sure that the argument KEYCLOAK_CONNECT_OPTIONS at index [0] is available in the KeycloakConnectModule context

it seems like registerAsync function is not compatible in this library

//app.module.ts

 @Module({
  imports: [
    KeycloakConnectModule.registerAsync({
      useClass: KeyCloakConfigService
    })
    ]

//config service


@Injectable()
export class KeyCloakConfigService implements KeycloakConnectOptionsFactory {
	constructor() {
		console.log('>>>>>>>>>KEY KEY>>>>>>>>>>>1 ,');
	}

	createKeycloakConnectOptions(): KeycloakConnectOptions | Promise<KeycloakConnectOptions> {

		return {
            authServerUrl: 'http://localhost:8082/auth',
            realm: 'master',
            clientId: 'nestjs-app',
            secret: '',
            logLevels: ['warn'],
            useNestLogger: false,
		};
	}
}

Any Help will be appreciated.
Thanks

How to use keycloak-connect as peer dependency?

Hi @ferrerojosh.

I really love your project and with the latest release there were some really helpful features. Regarding the introduction of keycloak-connect as peer dependency I might have a stupid question.

I forked this library, because I did some adjustments (https://www.npmjs.com/package/@ef-company/keycloak-connect). Now, I would like to use it instead of the original one and without forking your project. Could you give an example of how this could work? It would help me a lot.

Thanks in advance!

Secret key

Hi, why in keyckloak config secret is required? In keycloak-connect is not required.
What should i do if my client is public?

OptionalUnprotected decorator

Is there a way to have a single endpoint work with authenticated users, and no authenticated users? Without stripping away the authorization header?

I have a few use cases. For the commentSection, we have a single endpoint where we fetch the comments, not logged in users should be able to fetch comments. But when a user is logged in, the same endpoint should be usable, but it should also pass in the user object to the controller. Like this, we can have one endpoint that does multiple things based on if the user is logged in or not.

Not logged in user fetches comment:

{
  "_id": "LhNuJd15_X7",
  "author": "e3fc0911-b708-481e-b4fb-8c1c60a57c3d",
  "text": "test comment !",
  "isOwnComment": false
}

Logged in user1 fetches comment:

{
  "_id": "LhNuJd15_X7",
  "author": "e3fc0911-b708-481e-b4fb-8c1c60a57c3d",
  "text": "test comment !",
  "isOwnComment": true
}

This is a code I used with passport to create a decorator that would let users still query the endpoint even if they are not logged in, but it would provide the user object in the header.

import {
  createParamDecorator,
  ExecutionContext,
  Injectable,
} from '@nestjs/common'
import { AuthGuard } from '@nestjs/passport'
import { User } from '../user/user.model'

export const GetUser = createParamDecorator(
  (data, ctx: ExecutionContext): User => {
    const req = ctx.switchToHttp().getRequest()
    return req.user
  }
)

@Injectable()
export class AuthOptionalGuard extends AuthGuard('jwt') {
  async canActivate(context: any) {
    await super.canActivate(context)
    return true
  }

  handleRequest(err, user, info, context) {
    try {
      super.handleRequest(err, user, info, context)
    } catch (e) {
      // console.log(e)
    }
    if (user) {
      return user
    }
  }
}
 

is there a way to have similar functionality in this package? Right now when using @Unprotected strips away the authorization header when a logged-in user requests the endpoint.

Forbidden resource with GraphQL

I have one day trying to authenticate a GraphQL mutation without any success:

@Mutation((returns) => UsersType)
  @Roles('host', 'erasmus')
  createUser(@Args('createUserInput') createUserInput: CreateUserInput) {
    return this.usersService.createUser(createUserInput);
  }

I request the JWT token and i pass it ass a bearer token, it contains the required rol:

"typ": "Bearer",
  "azp": "macondo/frontend",
  "acr": "1",
  "realm_access": {
    "roles": [
      "offline_access",
      "host",
      "uma_authorization"
    ]
  },
  "resource_access": {
    "macondo/backend": {
      "roles": [
        "host"
      ]
    },
    "macondo/frontend": {
      "roles": [
        "host"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },
  "scope": "email profile",
  "email_verified": true,
  "preferred_username": "userhost",
  "locale": "tr"

The Keycloak settings are:

    KeycloakConnectModule.register({
      realm: process.env.KEYCLOAK_REALM,
      bearerOnly: true,
      authServerUrl: process.env.KEYCLOAK_SERVER_URL,
      clientId: process.env.KEYCLOAK_CLIENT_ID,
      secret: process.env.KEYCLOAK_SECRET,
      // cookieKey: 'KEYCLOAK_JWT',
    }),

where:

KEYCLOAK_CLIENT_ID=macondo/backend
KEYCLOAK_REALM=macondo
KEYCLOAK_SECRET=6cb0f7cb-38a4-4294-948b-b819bca69dd5
KEYCLOAK_SERVER_URL=http://localhost:8080/auth

At playground i try:
Screen Shot 2021-02-09 at 23 42 07

As you can see it does not get access to the resources.

Is use the unprotected or allow any rule decorator it works fine.

What's the missing thing here? Thank you very much.

Keycloak.json file config support

We just update our dependency to the latest version and we can't start our app using the keycloak.json configuration flow anymore. (v1.4 to v1.6)

Cannot read property 'useNestLogger' of null

There is a way to still use keycloak.json file with this version ?

Configuration of Role-based authentication

Hello I configured 'nest-keycloak-connect' and some endpoints with Role-based authentication. Everytime I try to do the actual api-call via swagger I get a 403 Forbidden Ressource Error.

What are the exact configurations you have to do in Keycloak?
I created a role (I tried realm and client role) and added my user to it. If I use the @AllowAnyRole()-decorator it works fine, thats why I think this could be a configuration issue.
Edit: seems to work now

Error if no logLevels property is defined

Hello,

this is my first issue here. I've been using this lib since version 1.3.1. Now I decided to update it to the latest version 1.5.2 but I got this error

TypeError: Cannot read property 'includes' of undefined
    at KeycloakLogger.isLogLevelEnabled (C:\...\node_modules\nest-keycloak-connect\logger.js:28:31)
    at KeycloakLogger.callWrapped (C:\...\node_modules\nest-keycloak-connect\logger.js:31:19)
    at KeycloakLogger.verbose (C:\...\node_modules\nest-keycloak-connect\logger.js:25:14)
    at AuthGuard.<anonymous> (C:\...\node_modules\nest-keycloak-connect\guards\auth.guard.js:75:25)
    at Generator.next (<anonymous>)
    at C:\...\node_modules\nest-keycloak-connect\guards\auth.guard.js:20:71
    at new Promise (<anonymous>)
    at __awaiter (C:\...\node_modules\nest-keycloak-connect\guards\auth.guard.js:16:12)
    at AuthGuard.canActivate (C:\...\node_modules\nest-keycloak-connect\guards\auth.guard.js:51:16)
    at GuardsConsumer.tryActivate (C:\...\node_modules\@nestjs\core\guards\guards-consumer.js:15:34)

My config was as follows

KeycloakConnectModule.registerAsync({
      useFactory: async (configService: ConfigService) => ({
        authServerUrl: configService.get<string>('HOST'),
        realm: configService.get<string>('REALM'),
        clientId: configService.get<string>('CID'),
        secret: configService.get<string>('SECRET')
      }),
      inject: [ConfigService]
    })

By the error message I figured it out that I was missing something so I got to the repo and I saw that there's a property that I didn't have: logLevels.

The solution is as simple as adding logLevels to the previous configuration, but the problem is that it didn't warn me about it and I see that the property is optional so there should be no error, or at least be more clear about it.

Thanks in advance!

How can i get client information ("id" not clientId) from access_token

Jwt only gives user information and clientId, how can I get ID of the client as shown in the image

I CAN GET CLIENT DETAILS FROM THIS URL
https://${SERVER_URL}/auth/admin/realms/master/clients?clientId=test
but i want to save my api call for getting Id

** I want to get client information "Id" within jwt**

Any help/information will be helpful for me.

image

Is it possible to protect ServeStatic and files?

Hi,

is there a way to protect static files?

  1. Serve static using https://docs.nestjs.com/recipes/serve-static

  2. Controller files. Accessible from the browser

@Get('download/:fileId')
async download(@Res() response: Response, @Param('fileId') fileId: string, @AuthenticatedUser() user) { 
  const file = getFile(filed)
  if(hasAccessToThisFile(file, user)) {
   response.download(file, 'myFile.pdf')
  }
}

accessible via browser "localhost:3333/files/download/MyFileId" (No authorization header)

Cannot read property 'undefined' of undefined when sending no cookies

Hi,

you had a change in 1.0.9 in auth.guard.ts:

Old
static extractJwtFromCookie(cookies: { [key: string]: string }) {
return cookies?.keycloakJWT;

New
extractJwtFromCookie(cookies: { [key: string]: string }) {
return cookies[this.keycloakOpts.cookieKey] || cookies.KEYCLOAK_JWT;
}

I think you lost a fix done from a feature request. Problem is now, that you get a "Cannot read property 'undefined' of undefined" when there is no cookie object. Could you please fix this and release a new version. 1.0.10 is not usable now if you do not send cookie.

Is it possible to change the realm on runtime?

We are building a multi tenant application where each sub domain would be one realm in keycloak, we are trying to see if there is a way we can set the realm dynamically from the subdomain?

Roles decorator

Hi,

The documentation on NPM speaks about a Roles decorator.
But it is nowhere to be found.
Is it possible to have this working?

Decorator for authenticated user

Hi John,

first of all thanks a lot for this package :)

While using your package i asked myself, how can i receive user information like the user id. After digging the code i saw that you already assign the user information to the request object. Maybe you should write that in the documentation because other people might have the same question.

P.S.: the following decorator might be some syntax sugar:

import { createParamDecorator, ExecutionContext } from "@nestjs/common"

export const AuthenticatedUser = createParamDecorator((_data: unknown, ctx: ExecutionContext) => {
  const req = ctx.switchToHttp().getRequest()
  return req.user
})

Have a nice day! :)

Remove the requirement for a clientSecret

In our use case, we set up a keycloak client to represent an application.

The client roles we assign to users in that single client are then used by both the web GUI and the API. We don't have to worry if our GUI and API roles are in sync.

I.e if a user is given the role create_purchase_order in a single client

  1. They will be able to access the create purchase order screen in the GUI
  2. The API will give them access to the /purchaseorder POST endpoint

If you are forced to use a secret to make your Keycloak client work with nest JS, then a second client is required for the GUI because keycloak-js does not allow a clientSecret in the browser for security reasons.

compatible with openid connect

in OIDC, client(browsers) only provide id_token(which typ is ID) to request API, access_token should be secured on server side

example of id_token

{
  "exp": 1606727804,
  "iat": 1606727504,
  "auth_time": 0,
  "jti": "5c7b0d2e-e046-4cb9-9c0d-4d6991a95eff",
  "iss": "https://{AS}/auth/realms/demo",
  "aud": "demo",
  "sub": "e44dfa3b-2141-431a-a43c-d16bfd3fba47",
  "typ": "ID",
  "azp": "demo",
  "session_state": "64e1e087-c136-4f56-9885-1cf6cc944b15",
  "at_hash": "mG3iE5wDLX7Z393G1GEMrg",
  "acr": "1",
  "email_verified": false,
  "clientHost": "{AS}",
  "clientId": "demo",
  "preferred_username": "service-account-demo",
  "clientAddress": "{AS}"
}

How to extend AuthGaurd Class Imported from 'nest-keycloak-connect'

I want to extend auth guard class for some custom functionality

I tried and it works well


  @Injectable()
  export class KeycloakAuthGuard extends AuthGuard implements CanActivate {
	canActivate(context: ExecutionContext) {
		const value = super.canActivate(context);
		const [request] = extractRequest(context);
		console.log(' ++++++++++++++++++ ++++++++++++++ ', request.user); //getting user here

		// Some Custom functionality here..... like call any external request

		return value;
	}
  }


But I need to add a constructor so that I can use some services here like HttpService
Can you please help me out how can I?

constructor(private http: HttpService) { super() // your contructor requires 4 arguments }

Grateful to you

FEATURE: Have a way to inject custom logger

Hi,

I'm using the nest-winston logger in my project, but when it is active, this package does not log anything, no matter the log level. However after I disable the winston logger it does. It would be nice to allow somehow to inject a logger instead of the default one here, or just be like "useIncludedLogger" where if false it naively instantiates a new logger trusing the nest framework to have one defined.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.