401 - Unauthorized from Azure AD with passport-azure-ad-oauth2

2.3k Views Asked by At

I'm trying to set up up passport with an oauth2 strategy using "passport-azure-ad-oauth2" towards Azure AD. It works fine with one tenant, but not another, even though they are set up the exact same way.

After being redirected to the Azure AD login and entering my username + password I'm redirected to the failureRedirect. If I disable the failureRedirect I'm sent to a URL that looks something like this http://localhost:3006/auth/login/azure/return?code="my token here"&session_state="my session state"

Azure issues my token, but when I'm sent to the returnURL I simply get "Unauthorized" and I never reach the callback, so not able to log out any error.

Azure AD manifest.json

{
    "id": "9c3-my-uuid",
    "acceptMappedClaims": null,
    "accessTokenAcceptedVersion": 2,
    "addIns": [],
    "allowPublicClient": null,
    "appId": "82b-my-uuid",
    "appRoles": [],
    "oauth2AllowUrlPathMatching": false,
    "createdDateTime": "2020-07-27T10:44:50Z",
    "groupMembershipClaims": null,
    "identifierUris": [
        "api://82b-my-uuid"
    ],
    "informationalUrls": {
        "termsOfService": null,
        "support": null,
        "privacy": null,
        "marketing": null
    },
    "keyCredentials": [],
    "knownClientApplications": [],
    "logoUrl": null,
    "logoutUrl": null,
    "name": "My company",
    "oauth2AllowIdTokenImplicitFlow": true,
    "oauth2AllowImplicitFlow": true,
    "oauth2Permissions": [
        {
            "adminConsentDescription": "Allows the app to read user info",
            "adminConsentDisplayName": "Read user info",
            "id": "c39-my-uuid",
            "isEnabled": true,
            "lang": null,
            "origin": "Application",
            "type": "User",
            "userConsentDescription": "Allows the app to read user info",
            "userConsentDisplayName": "Read user info",
            "value": "demo.read"
        }
    ],
    "oauth2RequirePostResponse": false,
    "optionalClaims": {
        "idToken": [],
        "accessToken": [],
        "saml2Token": []
    },
    "orgRestrictions": [],
    "parentalControlSettings": {
        "countriesBlockedForMinors": [],
        "legalAgeGroupRule": "Allow"
    },
    "passwordCredentials": [
        {
            "customKeyIdentifier": null,
            "endDate": "2299-12-30T23:00:00Z",
            "keyId": "e07-my-key",
            "startDate": "2020-07-27T10:57:53.945Z",
            "value": null,
            "createdOn": "2020-07-27T10:57:55.4720906Z",
            "hint": ".jq",
            "displayName": "my-displayname"
        }
    ],
    "preAuthorizedApplications": [
        {
            "appId": "82b-my-uuid",
            "permissionIds": [
                "c39-my-uuid"
            ]
        }
    ],
    "publisherDomain": "my-domain.com",
    "replyUrlsWithType": [
        {
            "url": "http://localhost:3006/auth/login/azure/return",
            "type": "Web"
        },
        {
            "url": "http://localhost:3006/customer/auth/login/azure/return",
            "type": "Web"
        }
    ],
    "requiredResourceAccess": [
        {
            "resourceAppId": "00000003-0000-0000-c000-000000000000",
            "resourceAccess": [
                {
                    "id": "64a6cdd6-aab1-4aaf-94b8-3cc8405e90d0",
                    "type": "Scope"
                },
                {
                    "id": "37f7f235-527c-4136-accd-4a02d197296e",
                    "type": "Scope"
                },
                {
                    "id": "14dad69e-099b-42c9-810b-d002981feec1",
                    "type": "Scope"
                },
                {
                    "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
                    "type": "Scope"
                }
            ]
        }
    ],
    "samlMetadataUrl": null,
    "signInUrl": null,
    "signInAudience": "AzureADMyOrg",
    "tags": [],
    "tokenEncryptionKeyId": null,
    "trustedCertificateSubjects": [],
    "verifiedPublisher": {
        "displayName": null,
        "verifiedPublisherId": null,
        "addedDateTime": null
    }
}
export class UserRouter {
    public router: Router;
    private azureAdOauth2 = new AzureAdOAuth2Strategy(
        {
            clientID: process.env.AZURE_OAUTH_CLIENT_ID,
            clientSecret: process.env.AZURE_OAUTH_CLIENT_SECRET,
            callbackURL: '/auth/login/azure/return',
            tenant: process.env.AZURE_OAUTH_TENANT,
        },
        async (accessToken, refreshToken, params, profile, done) => {
            const decodedToken = jwt.decode(accessToken);

            await Utils.checkLogin({ email: decodedToken.email, password: null, localUser: false, isInternal: true })
                .then(user => {
                    const permissions = Utils.populatePermission(user);

                    const token = issueJWT(user);

                    const accessObject = {
                        token,
                        user,
                        permissions,
                    };

                    return done(null, accessObject);
                })
                .catch(error => {
                    return done(null, false, error);
                });
        }
    );
    constructor() {
        this.router = Router();
        this.init();
    }
    public init() {
        this.router.use(cors());
        this.router.post('/login', AuthController.login);
        this.router.get(
            '/login/azure',
            passport.authenticate(
                this.azureAdOauth2,
                { session: false, prompt: 'select_account' },
                (err, user, info) => {
                    console.log(err);
                }
            )
        );
        this.router.get(
            '/login/azure/return',
            passport.authenticate(this.azureAdOauth2, {
                session: false,
                failureRedirect: `${process.env.CLIENT_UI}/login?status=failed`,
                passReqToCallback: true,
            }),
            (req: IGetUserAuthInfoRequest, res) => {
                res.cookie('my_jwt', (req.user as any).token, {
                    httpOnly: false,
                    expires: new Date(Date.now() + 24 * 3600000),
                }).redirect(process.env.CLIENT_UI + '/login?status=success');
            }
        );
        this.router.put('/forgot-password/:email/', UserController.setVerificationToken);
        this.router.put('/change-forgotten-password/:email/', UserController.changePasswordWithVerificationToken);
    }
}
const userRoutes = new UserRouter();
userRoutes.init();
export default userRoutes.router;

Error

If I go to the enterprise application in Microsoft Azure Portal I can see the sign-in activity under "Sign-ins".

For each login attempt I get one successful event, and one "interrupted" with failure reason "Either multiple user identities are available for the current request or selected account is not supported for the scenario." and Sign-in error code: 16000

0

There are 0 best solutions below