GRANTED Module for Nestjs
This module allow you to use RBAC security on your endpoints nestjs
Install @hhnest/granted
You can use either the npm or yarn command-line tool to install the package
.
Use whichever is appropriate for your project in the examples below.
NPM
# @hhnest/granted
npm install @hhnest/granted --save
YARN
# @hhnest/granted
yarn add @hhnest/granted
Peer dependencies
name | version |
---|---|
@nestjs/common | ^10.0.0 |
@nestjs/core | ^10.0.0 |
@nestjs/platform-express | ^10.0.0 |
Dependencies
name | version |
---|---|
jsonwebtoken | ^9.0.0 |
Configuration
Just import the module GrantedModule
, specify the implementation for fetch username, roles and you can use the annotations
.
Header provider
AppModule.ts
@Module({
// Declare the module and define the option apply (for apply or not the security)
imports: [
GrantedModule.forRoot({apply: environment.applyAuthGuard}),
],
})
export class AppModule {}
Jwt Provider
AppModule.ts
@Module({
// Declare the module and define the option apply (for apply or not the security) and GrantedInfoJwtProvider (for decode user info from jwt token)
imports: [
GrantedModule.forRoot({apply: environment.applyAuthGuard, infoProvider: new GrantedInfoJwtProvider({
algorithm: 'RS256', // RS256, EC256, PS256
pemFile: 'path/jwt_public_key.pem',
// or
base64Key: '-----BEGIN PUBLIC KEY-----\nBASE64KEYENCODED\n-----END PUBLIC KEY-----'
})}),
],
})
export class AppModule {}
Use
Inject informations
The module allow you to inject informations in your endpoints:
@Get('username')
username(@Username() userId: string): Observable<string> {
return of(userId);
}
@Get('roles')
roles(@Roles() roles: string[]): Observable<string[]> {
return of(roles);
}
@Get('groups')
groups(@Groups() groups: string[]): Observable<string[]> {
return of(groups);
}
@Get('locale')
groups(@Locale() locale: string): Observable<string> {
return of(locale);
}
Secure endpoints
@Get('username')
@GrantedTo(and(isAuthenticated(), hasRole('GET_USERNAME')))
username(@Username() userId: string): Observable<string> {
return of(userId);
}
Details
GrantedTo(...booleanSpecs: BooleanSpec[])
// AndSpec
and(...booleanSpecs: BooleanSpec[]): BooleanSpec
// IsTrueSpec
isTrue(): BooleanSpec
// HasRoleSpec
hasRole(role: string): BooleanSpec
// IsAuthenticatedSpec
isAuthenticated(): BooleanSpec
// IsFalseSpec
isFalse(): BooleanSpec
// NotSpec
not(booleanSpec: BooleanSpec): BooleanSpec
// OrSpec
or(...booleanSpecs: BooleanSpec[]): BooleanSpec
// IsUserSpec
isUser(type: 'Param' | 'Query' | 'Body', field?: string): BooleanSpec
User informations provider
2 providers information are provide by GrantedModule
GrantedInfoProvider
GrantedInfoJwtProvider
GrantedInfoProvider
get user information directly in headers
username
roles
groups
locale
GrantedInfoJwtProvider
get information from JWT token (since 1.0.3)
if token provide username
/roles
/groups
informations will be available
locale
is still get from header
You have to provide a public RSA key for verify the token
AppModule.ts
import { GrantedModule } from '@hhnest/granted';
import { GrantedInfoJwtProvider } from '@hhnest/granted/services';
@Module({
imports: [
GrantedModule.forRoot({infoProvider: new GrantedInfoJwtProvider('-----BEGIN PUBLIC KEY-----\nMIIBIj...IDAQAB\n-----END PUBLIC KEY-----', 'RS256')}),
],
})
export class AppModule {}
Extends
AppRbacGuard read information in http headers request
username, roles, groups and accept-language
If you want to extract information from other behaviors, just write an other implementation of IGrantedInfoProvider and set on option
AppModule.ts
@Module({
// Declare the module and define the option apply (for apply or not the security)
providers: [MyGrantedInfoProvider],
imports: [
GrantedModule.forRoot({apply: environment.applyAuthGuard, infoProvider: new MyGrantedInfoProvider()}),
],
})
export class AppModule {}
This is actualy the default provider that get information simply from headers
Note that you have to manage 2 cases: Request
and IncomingMessage
export class MyGrantedInfoProvider implements IGrantedInfoProvider {
getUsernameFromRequest(request: Request): string {
return JSON.parse(request.header('username') || 'anonymous');
}
getRolesFromRequest(request: Request): string[] {
return JSON.parse(request.header('roles') || '[]');
}
getGroupsFromRequest(request: Request): string[] {
return JSON.parse(request.header('groups') || '[]');
}
getLocaleFromRequest(request: Request): string {
return request.header('accept-language') || 'en';
}
getUsernameFromIncomingMessage(incomingMessage: IncomingMessage): string {
return JSON.parse(incomingMessage.headers('username') || 'anonymous');
}
getRolesFromIncomingMessage(incomingMessage: IncomingMessage): string[] {
return JSON.parse(incomingMessage.headers['roles'] as string || '[]')
}
getGroupsFromIncomingMessage(incomingMessage: IncomingMessage): string[] {
return JSON.parse(incomingMessage.headers['groups'] as string || '[]')
}
getLocaleFromIncomingMessage(incomingMessage: IncomingMessage): string {
return incomingMessage.headers['accept-language'] || 'en';
}
}