Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

nest-keycloak-connect

Package Overview
Dependencies
Maintainers
1
Versions
57
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nest-keycloak-connect - npm Package Compare versions

Comparing version 1.9.5 to 1.10.0

6

dist/interface/keycloak-connect-options.interface.d.ts

@@ -19,3 +19,7 @@ import { LogLevel } from '@nestjs/common';

*/
realmSecretResolver?: (realm: string) => Promise<string> | string;
realmSecretResolver?: (realm: string, request?: any) => Promise<string> | string;
/**
* The realm auth server url resolver function.
*/
realmAuthServerUrlResolver?: (realm: string, request?: any) => Promise<string> | string;
}

@@ -22,0 +26,0 @@ /**

8

dist/keycloak-connect.module.js

@@ -68,4 +68,4 @@ "use strict";

provide: constants_1.KEYCLOAK_MULTITENANT_SERVICE,
useClass: keycloak_multitenant_service_1.KeycloakMultiTenantService
}
useClass: keycloak_multitenant_service_1.KeycloakMultiTenantService,
},
];

@@ -95,4 +95,4 @@ return {

provide: constants_1.KEYCLOAK_MULTITENANT_SERVICE,
useClass: keycloak_multitenant_service_1.KeycloakMultiTenantService
}
useClass: keycloak_multitenant_service_1.KeycloakMultiTenantService,
},
];

@@ -99,0 +99,0 @@ if (options.useExisting || options.useFactory) {

@@ -17,6 +17,8 @@ import KeycloakConnect from 'keycloak-connect';

* @param realm the realm to retrieve from
* @param request the request instance, defaults to undefined
* @returns the multi tenant keycloak instance
*/
get(realm: string): Promise<KeycloakConnect.Keycloak>;
resolveSecret(realm: string): Promise<string>;
get(realm: string, request?: any): Promise<KeycloakConnect.Keycloak>;
resolveAuthServerUrl(realm: string, request?: any): Promise<string>;
resolveSecret(realm: string, request?: any): Promise<string>;
}

@@ -48,5 +48,6 @@ "use strict";

* @param realm the realm to retrieve from
* @param request the request instance, defaults to undefined
* @returns the multi tenant keycloak instance
*/
get(realm) {
get(realm, request = undefined) {
return __awaiter(this, void 0, void 0, function* () {

@@ -60,6 +61,10 @@ if (typeof this.keycloakOpts === 'string') {

}
const authServerUrl = yield this.resolveAuthServerUrl(realm, request);
const secret = yield this.resolveSecret(realm, request);
// Check if existing
if (this.instances.has(realm)) {
// If resolve always is enabled, resolve everything again
if (this.keycloakOpts.multiTenant.resolveAlways) {
const keycloak = this.instances.get(realm);
const secret = yield this.resolveSecret(realm);
keycloak.config.authServerUrl = authServerUrl;
keycloak.config.secret = secret;

@@ -71,9 +76,10 @@ keycloak.grantManager.secret = secret;

}
// Otherwise return the instance
return this.instances.get(realm);
}
else {
const secret = yield this.resolveSecret(realm);
// TODO: Repeating code from provider, will need to rework this in 2.0
// Override realm and secret
// Override realm, secret, and authServerUrl
const keycloakOpts = Object.assign(this.keycloakOpts, {
authServerUrl,
realm,

@@ -88,2 +94,3 @@ secret,

};
// Save instance
this.instances.set(realm, keycloak);

@@ -94,3 +101,3 @@ return keycloak;

}
resolveSecret(realm) {
resolveAuthServerUrl(realm, request = undefined) {
return __awaiter(this, void 0, void 0, function* () {

@@ -104,4 +111,38 @@ if (typeof this.keycloakOpts === 'string') {

}
// If no realm auth server url resolver is defined, return defaults
if (!this.keycloakOpts.multiTenant.realmAuthServerUrlResolver) {
return (this.keycloakOpts.authServerUrl ||
this.keycloakOpts['auth-server-url'] ||
this.keycloakOpts.serverUrl ||
this.keycloakOpts['server-url']);
}
// Resolve realm authServerUrl
const resolvedAuthServerUrl = this.keycloakOpts.multiTenant.realmAuthServerUrlResolver(realm, request);
const authServerUrl = resolvedAuthServerUrl || resolvedAuthServerUrl instanceof Promise
? yield resolvedAuthServerUrl
: resolvedAuthServerUrl;
// Override auth server url
// Order of priority: resolved realm auth server url > provided auth server url
return (authServerUrl ||
this.keycloakOpts.authServerUrl ||
this.keycloakOpts['auth-server-url'] ||
this.keycloakOpts.serverUrl ||
this.keycloakOpts['server-url']);
});
}
resolveSecret(realm, request = undefined) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof this.keycloakOpts === 'string') {
throw new Error('Keycloak configuration is a configuration path. This should not happen after module load.');
}
if (this.keycloakOpts.multiTenant === null ||
this.keycloakOpts.multiTenant === undefined) {
throw new Error('Multi tenant is not defined yet multi tenant service is being called.');
}
// If no realm secret resolver is defined, return defaults
if (!this.keycloakOpts.multiTenant.realmSecretResolver) {
return this.keycloakOpts.secret;
}
// Resolve realm secret
const resolvedRealmSecret = this.keycloakOpts.multiTenant.realmSecretResolver(realm);
const resolvedRealmSecret = this.keycloakOpts.multiTenant.realmSecretResolver(realm, request);
const realmSecret = resolvedRealmSecret || resolvedRealmSecret instanceof Promise

@@ -108,0 +149,0 @@ ? yield resolvedRealmSecret

@@ -19,3 +19,3 @@ "use strict";

const realm = resolvedRealm instanceof Promise ? yield resolvedRealm : resolvedRealm;
return yield multiTenant.get(realm);
return yield multiTenant.get(realm, request);
}

@@ -25,3 +25,3 @@ else if (!opts.realm) {

const issuerRealm = payload.iss.split('/').pop();
return yield multiTenant.get(issuerRealm);
return yield multiTenant.get(issuerRealm, request);
}

@@ -28,0 +28,0 @@ return singleTenant;

{
"name": "nest-keycloak-connect",
"version": "1.9.5",
"version": "1.10.0",
"description": "keycloak-nodejs-connect module for Nest",

@@ -49,3 +49,3 @@ "author": "John Joshua Ferrer <johnjoshuaferrer@disroot.org>",

"@nestjs/graphql": ">=6",
"keycloak-connect": ">=10.0.0 <24.0.0"
"keycloak-connect": ">=10.0.0 <25.0.0"
},

@@ -67,3 +67,3 @@ "devDependencies": {

"graphql": "^16.6.0",
"keycloak-connect": "18.0.2",
"keycloak-connect": "24.0.1",
"prettier": "1.19.1",

@@ -70,0 +70,0 @@ "reflect-metadata": "0.1.13",

@@ -40,2 +40,3 @@ # Nest Keycloak Connect

Registering the module:
```typescript

@@ -46,24 +47,30 @@ KeycloakConnectModule.register({

clientId: 'my-nestjs-app',
secret: 'secret',
secret: 'secret',
policyEnforcement: PolicyEnforcementMode.PERMISSIVE, // optional
tokenValidation: TokenValidation.ONLINE, // optional
})
});
```
Async registration is also available:
```typescript
KeycloakConnectModule.registerAsync({
useExisting: KeycloakConfigService,
imports: [ConfigModule]
})
imports: [ConfigModule],
});
```
#### KeycloakConfigService
```typescript
import { Injectable } from '@nestjs/common';
import { KeycloakConnectOptions, KeycloakConnectOptionsFactory, PolicyEnforcementMode, TokenValidation } from 'nest-keycloak-connect';
import {
KeycloakConnectOptions,
KeycloakConnectOptionsFactory,
PolicyEnforcementMode,
TokenValidation,
} from 'nest-keycloak-connect';
@Injectable()
export class KeycloakConfigService implements KeycloakConnectOptionsFactory {
createKeycloakConnectOptions(): KeycloakConnectOptions {

@@ -78,3 +85,3 @@ return {

};
}
}
}

@@ -89,3 +96,3 @@ ```

tokenValidation: TokenValidation.ONLINE,
})
});
```

@@ -98,7 +105,9 @@

#### Global registration using APP_GUARD token
***NOTE: These are in order, see https://docs.nestjs.com/guards#binding-guards for more information.***
**_NOTE: These are in order, see https://docs.nestjs.com/guards#binding-guards for more information._**
```typescript
providers: [
{
provide: APP_GUARD,
provide: APP_GUARD,
useClass: AuthGuard,

@@ -114,5 +123,7 @@ },

},
]
];
```
#### Scoped registration
```typescript

@@ -127,10 +138,13 @@ @Controller('cats')

### 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](#nest-keycloak-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.***
**_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.

@@ -144,3 +158,9 @@ Permissive by default. Used by controller methods annotated with `@Roles` (matching can be configured)

```typescript
import { Resource, Roles, Scopes, Public, RoleMatchingMode } from 'nest-keycloak-connect';
import {
Resource,
Roles,
Scopes,
Public,
RoleMatchingMode,
} from 'nest-keycloak-connect';
import { Controller, Get, Delete, Put, Post, Param } from '@nestjs/common';

@@ -199,3 +219,3 @@ import { Product } from './product';

| Decorator | Description |
|--------------------|-----------------------------------------------------------------------------------------------------------|
| ------------------ | --------------------------------------------------------------------------------------------------------- |
| @AuthenticatedUser | Retrieves the current Keycloak logged-in user. (must be per method, unless controller is request scoped.) |

@@ -209,3 +229,5 @@ | @EnforcerOptions | Keycloak enforcer options. |

## Multi tenant configuration
Setting up for multi-tenant is configured as an option in your configuration:
```typescript

@@ -220,5 +242,9 @@ {

},
realmSecretResolver: (realm) => {
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];
}

@@ -232,24 +258,28 @@ }

### Keycloak Options
For Keycloak options, refer to the official [keycloak-connect](https://github.com/keycloak/keycloak-nodejs-connect/blob/main/middleware/auth-utils/config.js) 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](#multi-tenant-options) | no | - |
| roleMerge | Sets the merge mode for @Role decorator | no | OVERRIDE |
| 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](#multi-tenant-options) | 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 returns the secret string | yes | - |
| 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](example) is provided in the source code with both Keycloak Realm and Postman requests for you to experiment with.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc