Search code examples
azure-active-directorymicrosoft-graph-apiopenid

Can I get an id_token from Azure AD for my app?


Using the client_credentials flow in Azure AD, I am unable to retrieve an id_token for my app.

I am experimenting with the Azure AD OAuth/OpenID endpoints, and running into some questions.

I create a simple app with minimal config through the Graph API (a beta endpoint, but still). I have removed all the headers and anonymised in code snippets below:

curl -X POST \
  https://graph.microsoft.com/beta/applications \
  -d '{
    "displayName": "App Name",
    "passwordCredentials": [
        {
            "endDateTime": "2299-12-30T23:00:00Z",
            "startDateTime": "2019-02-14T20:19:14.686691Z",
            "secretText": "<SOME KEY>",
            "displayName": "Client Secret"
        }
    ]
}'

In the response from Azure AD, I get an appId:

{
    "@odata.context": "https://graph.microsoft.com/beta/$metadata#applications/$entity",
    "id": "<SOME GUID>",
    "deletedDateTime": null,
    "isFallbackPublicClient": null,
    "appId": "<SOME GUID>",
    ...

This is enough for me to be able to retrieve an access_token from the v1 OAuth endpoint:

curl -X POST \
  https://login.microsoftonline.com/tenant_id/oauth2/token \
  -d 'client_id=appId&client_secret=secretText&grant_type=client_credentials'

Response:

{
    "token_type": "Bearer",
    "expires_in": "3600",
    "ext_expires_in": "3600",
    "expires_on": "1550220412",
    "not_before": "1550216512",
    "resource": "00000002-0000-0000-c000-000000000000",
    "access_token": "<JWT access token>"
}

Since I didn't specify a resource in my call, I get the default Graph API resource.

Now, what I also would like to get is an id_token for my app. I have been able to get these tokens from other OpenID providers. However, the OpenID Connect Core spec. gives me reason to think that id_tokens are for end users only, not apps:

"The ID Token is a security token that contains Claims about the Authentication of an End-User by an Authorization Server when using a Client, and potentially other requested Claims"

(From https://openid.net/specs/openid-connect-core-1_0.html#IDToken)

Adding resource=openid to the POST to the token endpoint above won't work, since openid is a scope, not a resource.

Switching to the v2 endpoints, I get access to a scope parameter. I can obtain an access token from there by setting scope=https://graph.microsoft.com/.default, explicitly requesting the access I got by default through the v1 endpoint.

However, setting the scope to for instance scope=https://graph.microsoft.com/.default openid does not give me an id_token for my app, and the access token looks identical to the previous call.

Trying just scope=openid gives me the following error from Azure AD:

AADSTS70011: The provided request must include a 'scope' input parameter. The provided value for the input parameter 'scope' is not valid. The scope openid is not valid.

All this combined leads me to believe that the OpenID providers I have used and have issued id_tokens through the client_credentials flow are breaking the spec, and that id_tokens can only be obtained for end users (using the authorization_code flow gives me an id_token from Azure AD for myself without any issues).

Is this a correct conclusion, or can I force Azure AD to issue id_tokens to apps as well as end users?


Solution

  • An id_token is issued when a user signs-in. Client credentail flows have no user, so no id_token is issued.

    you'd need to use a flow like authorization code grant or openID connect to sign a user in. The response will have a id_token.