Access Token has the wrong TenantID

JAL 591 Reputation points
2020-10-12T07:09:30.237+00:00

I have a Web API. My database has a list of approved TenantIDs.

So I thought to myself - the security here is doable. I'll just check the Access Token for the TenantID.

What I didn't know is that AD will happily grant a token even if the clientID and TenantID are a mismatch.

Admittedly I can check the clientID in the token, but I wanted more than that - I wanted assurance that the clientID was created in a Tenant on my approved list.

So here's how I found this out. For testing, I called AcquireTokenAsync in hopes of querying my own Web API (using httpClient), with different Authorities (but same clientID)

string Authority = "https://login.microsoftonline.com/<TenantID-1>"
string Authority = "https://login.microsoftonline.com/<TenantID-2>"
string Authority = "https://login.microsoftonline.com/<TenantID-3>"

In each case, AD happily granted me an access token containing that clientID-plus-TenantID, even though the TenantID was a mismatch to that clientID.

How can I prevent this? Is there anything that my Web API can do to check for this discrepancy and auto-reject such a mismatched token?

Microsoft Entra ID
Microsoft Entra ID
A Microsoft Entra identity service that provides identity management and access control capabilities. Replaces Azure Active Directory.
23,307 questions
0 comments No comments
{count} votes

Accepted answer
  1. AmanpreetSingh-MSFT 56,761 Reputation points
    2020-10-12T08:55:35.927+00:00

    Hello @JAL · This is expected in case of Multi-Tenant application. As when a multi-tenant application registered in one tenant is accessed by users in different tenant and they accept the consent prompt, a service principal with same ClientID is created in that tenant as well. Which is why technically there is no mismatch in client ID and tenant ID in that case.

    In case of multi-tenant applications, authentication request is sent to https://login.microsoftonline.com/common or https://login.microsoftonline.com/organizations and the tenant discovery is done on the basis of the domain name in the UPN suffix of the user. Whereas, in case of single tenant apps, we use specific authority e.g. https://login.microsoftonline.com/tenantname.onmicrosoft.com or https://login.microsoftonline.com/tenant-guid. We cannot specify multiple tenants here as users has to be redirected to a specific url.

    In order to restrict users from specific organizations from signing-in your web api, you need to validate the authority/issuer of the tokens and accept tokens only from specified authorities.

    -----------------------------------------------------------------------------------------------------------

    Please "Accept the answer" if the information helped you. This will help us and others in the community as well.

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. JAL 591 Reputation points
    2020-10-12T12:45:06.003+00:00

    Thanks for your help.

    Yes I agree that issuer validation is necessary but I thought I could do this manually. Unfortunately the token has the issuer like this (depending on which TenantID was used as the Authority).

    "iss": "https://sts.windows.net/<TenantID-1>"
    "iss": "https://sts.windows.net/<TenantID-2>"
    "iss": "https://sts.windows.net/<TenantID-3>"

    Manual validation was failing. Based on your post, I re-thought the issue, seems I'll need to set ValidateIssuer = true for automatic validation - I guess the library will use some algorithm that detects the mismatch? Hopefully?

    You said, "When a multi-tenant application registered in one tenant is accessed by users in different tenant and they accept the consent prompt, a service principal with same ClientID is created in that tenant as well."

    Oddly, your words didn't apply to my manual-validation-scenario. Somehow, with ValidateIssuer = false, these other orgs can query my Web API even without a service principal. I logged into those orgs and verified - no Enterprise App exists. And my boss confirmed that he hasn't put in a ticket for admin consent.

    1 person found this answer helpful.
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.