Skip to content

A Global Nest module to validate Azure Active Directory Tokens.

License

Notifications You must be signed in to change notification settings

benMain/nest-azure-ad-jwt-validator

Repository files navigation

Nest Azure Active Directory Token Validator

Azure Ad Logo

Description

Nest framework Module for validating Azure AD JWT Tokens.
The Module exports an AzureTokenValidationService for validating tokens as well as a guard you might consider using AzureActiveDirectoryGuard.
Note: The exported guard expects the jwt(json web token) in an authtoken header (in Aws APIGateway we don't like to mess with the Authorization header).

Installation

$ npm install --save nest-azure-ad-jwt-validator

Usage

  1. Import the module globally in your app module.
  2. Add the Exported Guard as a global guard or use the exported service
import {
  AzureActiveDirectoryGuard,
  NestAzureAdJwtValidatorModule,
} from 'nest-azure-ad-jwt-validator';
import { APP_GUARD } from '@nestjs/core';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { Module } from '@nestjs/common';
@Module({
  imports: [
    NestAzureAdJwtValidatorModule.forRoot({
      apps: [
        {
          tenantId: '63fca94a-4979-4ee1-b9cc-54169f68ccbf',
          audienceId: '6747e462-323d-4fb7-b1e0-ef99531fe611',
        },
      ],
      serviceTokens: ['random-string-generated-by-you'], // option - used to allow service-to-service communication, ala AWS x-api-key
      enableDebugLogs: true, // optional - false by default
      tokenHeader: 'authorization' // The Header in which the jwt appears defaults to 'authtoken' by default.
    }),
  ],
  controllers: [AppController],
  providers: [
    AppService,
    {
      provide: APP_GUARD,
      useClass: AzureActiveDirectoryGuard,
    },
  ],
})
export class AppModule {}

Azure Roles

To use azure roles go to portal.azure.com -> search for App Registrations -> find your app -> edit manifest

Add your roles to the manifest, the id's should be different Guids:

{
	"id": "xxxx-xxxx-xx-xxxx-xxxxxxx",
	...
	"appRoles": [
		{
			"allowedMemberTypes": [
				"User"
			],
			"description": "Admin Users",
			"displayName": "Admin",
			"id": "xxxxx-xxxx-xxx-xxx-xxxxxx",
			"isEnabled": true,
			"lang": null,
			"origin": "Application",
			"value": "Admin"
		},
		{
			"allowedMemberTypes": [
				"User"
			],
			"description": "Finance Users have the ability to update finance data.",
			"displayName": "FinanceUsers",
			"id": "xxxxxx-xxx-xxxx-xxxx-xxxxxx2",
			"isEnabled": true,
			"lang": null,
			"origin": "Application",
			"value": "FinanceUsers"
    },
    ...
	],
	"oauth2AllowUrlPathMatching": false,
	...
}

Next go to Enterprise Applications -> search for your app and click on it for details -> Users and Groups (or Assign Users and Groups) -> Add User -> Here you pick azure ad users or groups and put them into the App Roles

Now that Azure roles are setup and returned in the token, roles can be added to the application under the routes such as appmodule.ts

import {
  AzureActiveDirectoryGuard,
  NestAzureAdJwtValidatorModule,
} from 'nest-azure-ad-jwt-validator';
import { APP_GUARD } from '@nestjs/core';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { Module } from '@nestjs/common';
@Module({
  imports: [
    NestAzureAdJwtValidatorModule.forRoot({
      apps: [
        {
          tenantId: '63fca94a-4979-4ee1-b9cc-54169f68ccbf',
          audienceId: '6747e462-323d-4fb7-b1e0-ef99531fe611',
        },
      ],
      serviceTokens: ['random-string-generated-by-you'], // option - used to allow service-to-service communication, ala AWS x-api-key
      enableDebugLogs: true, // optional - false by default
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

controller.ts

import { Controller, Get } from '@nestjs/common';
import { AzureActiveDirectoryGuard } from 'nest-azure-ad-jwt-validator';
import { Roles } from 'nest-azure-ad-jwt-validator';
@UseGuards(AzureActiveDirectoryGuard)
@Controller('test')
export class TestController {
  @Get('')
  @Roles('admin', 'finance')
  get getTest() {
    return 'success';
  }
}

Or if you do not wish to add the guard globally to all endpoints you can specify specific controllers to have the guard such as:

import { Controller, Get } from '@nestjs/common';
import { Roles } from 'nest-azure-ad-jwt-validator';
@Controller('test')
export class TestController {
  @Get('')
  @Roles('admin', 'finance')
  get getTest() {
    return 'success';
  }
}

Note: Azure Roles have not been setup an a @Controller level that will require a code change to context.getHandler() -> context.getClass()

Note: If the role does not exist on the role, no roles are checked and everything proceeds as if there are no roles.

Note: If you are assigning users to appRoles via Azure Groups then you need to change the manifest

"groupMembershipClaims": null,

To

"groupMembershipClaims": "All", # or “SecurityGroups”

In addition you cannot nest security groups, so you cannot take an existing group and add it to the group assigned to the appRole.

Example: appRole: 'Admin' User: '[email protected]' AD Groups: 'AD-TEST-UI-UG'

Either add ADGroups to the appRole or add the user to the appRole. You cannot add the AD Group 'AD-TEST-UI-UG' to another AD Group superset ('AD-TEST-UI-SUPERSET-UG') group. 'AD-TEST-UI-SUPERSET-UG' would never show roles.

Also: Vote for this Feature15718164-add-support-for-nested-groups-in-azure-ad-app-acc In the Important section

Commit Messages

Commit messages should follow the [semantic commit message by angular(https://nitayneeman.com/posts/understanding-semantic-commit-messages-using-git-and-angular/)

git commit -am "fix(roles): add service token except to roles authorization" -m "The roles authorization should not run when the service now token is used because the service token is used when the application has no auth mechanism. Add warning message if user's roles does not match expected role" -m "PR Close #13"

Test

# unit tests
$ npm run test

# test coverage
$ npm run test:cov

Stay in touch

License

nest-azure-ad-jwt-validator is MIT licensed.