To resolve this issue, I replaced the tenant ID with the keyword common
in the authorizationURL
and tokenURL
. This allows users from any Azure AD tenant, including personal Microsoft accounts, to authenticate.
Below is my oAuth strategy Code.
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { Strategy, VerifyCallback } from 'passport-azure-ad-oauth2';
import { AuthService } from './auth.service';
import { ConfigService } from '@nestjs/config';
import axios from 'axios';
@Injectable()
export class OauthStrategy extends PassportStrategy(Strategy, 'azure-ad') {
constructor(
private readonly authService: AuthService,
private readonly configService: ConfigService
) {
super({
clientID: this.configService.get<string>('AZURE_CLIENT_ID'),
clientSecret: this.configService.get<string>('AZURE_CLIENT_SECRET'),
callbackURL: this.configService.get<string>('AZURE_CALLBACK_URL'),
authorizationURL: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
tokenURL: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
scope: [
'openid',
'User.Read',
'profile',
'email',
'Mail.Read',
'Mail.ReadBasic',
],
});
}
async validate(
accessToken: string,
refreshToken: string,
params: any,
profile: any,
done: VerifyCallback
): Promise<any> {
try {
const userProfile = await this.getUserProfile(accessToken);
const user = await this.authService.validateUser(userProfile);
if (!user) {
throw new UnauthorizedException();
}
done(null, user);
} catch (error) {
done(error, false);
}
}
async getUserProfile(accessToken: string): Promise<any> {
const graphUrl = 'https://graph.microsoft.com/v1.0/me';
const response = await axios.get(graphUrl, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
return response.data;
}
}