Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement Passport.js Azure AD Bearer Strategy ( OpenID ) in NestJS

Following the documentation for nestjs and passport I have the following implementation.

I started with the default nest cli setup, nest new auth-test I then added an auth folder under the src folder where the aad-auth.gaurd, aad.strategy and auth.module below sit.

I then added the new guard to the default route in the app.controller.ts

I confirmed the Azure App Registration setup by using it successfully as a C# Web API, so the Azure side is setup correctly.

I don't need to issue a JWT as that is issues in the front end by Azure AD, that bearer token is passed to the API in the header. There are no helpful errors, simply a 500 Internal Error. I notice a lot of Github requests for documentation on implementing Azure AD with nest, along with any OAuth flow provider (facebook, google) but as yet that request is still open.

Not sure what is implemented wrong, any guidance or suggestions would be appreciated on fixing the below code.

Documentation: NestJS : https://docs.nestjs.com/techniques/authentication Passport : http://www.passportjs.org/packages/passport-azure-ad/

//auth/aad.strategy.ts

import { BearerStrategy } from 'passport-azure-ad';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, ValidationPipe } from '@nestjs/common';

@Injectable() 
export class AADStrategy extends PassportStrategy(BearerStrategy) {
    constructor () {
        super({
            identityMetadata: "https://login.microsoftonline.com/<tenant>.onmicrosoft.com/v2.0/.well-known/openid-configuration",
            clientID: "<clientid>",
            issuer: null,
            audience: null,
            loggingLevel: "info",
            passReqToCallback: false
        })
    }

    async validate(payload: any){
        console.log(payload);
        return(payload);    
    }
}

//auth/aad-auth.gaurd

import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class AADAuthGaurd extends AuthGuard('aad') {}

//auth/auth.module.ts

import { Module } from '@nestjs/common';
import { AADStrategy } from './aad.strategy'

@Module({
    imports: [
        AADStrategy,
    ],
    providers: [
        AADStrategy,
    ]
})
export class AuthModule {}

//app.controller.ts

import { Controller, Get, UseGuards } from '@nestjs/common';
import { AppService } from './app.service';
import { AADAuthGaurd } from './auth/aad-auth.gaurd';


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

  @UseGuards(AADAuthGaurd)
  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}
like image 990
Terry Avatar asked Mar 04 '20 16:03

Terry


1 Answers

I resolved the issue, here is the working code condensed to one file.

//app.controller.ts
    import { Controller, Get, Injectable, UseGuards } from '@nestjs/common';
    import { AppService } from './app.service';
    import { AuthGuard, PassportStrategy } from "@nestjs/passport";
    import { BearerStrategy } from 'passport-azure-ad'
    
    @Injectable()
    export class AzureADStrategy extends PassportStrategy(BearerStrategy, 'oauth-bearer')
    {
      constructor()
      {
        super({
          identityMetadata: `https://login.microsoftonline.com/<tenant>.onmicrosoft.com/.well-known/openid-configuration`,
          clientID: 'client id from azure app',
        })
      }
    
      async validate(response: any)
      {
        const { unique_name }: {unique_name: string} = response;
        if (unique_name) return unique_name;
        else return null;
      }
    }
    
    @Controller()
    export class AppController {
      constructor() {}
    
      @Get('unprotected')
      unprotected() : string {
        return 'Unprotected';
      }
    
      @UseGuards(AuthGuard('oauth-bearer'))
      @Get('protected')
      protected() : string {
        return 'Protected';
      }
    }
like image 150
Terry Avatar answered Nov 05 '22 04:11

Terry