Cannot access OpenID connect UserInfo endpoint of AzureAD - azure-active-directory

I see that the userinfo endpoint is present on AzureAD OpenID Connect .well-known result. I want to access their UserInfo endpoint. I'm aware I will get the error if used with JWT tokens,
error_description="AADSTS90010: JWT tokens cannot be used with the UserInfo endpoint."
How can I retrieve these non-JWT tokens? I saw a stack overflow thread (Cannot access OpenId UserInfo endpoint on Azure (AADSTS90010: JWT tokens cannot be used with the UserInfo endpoint)) that said 'you can acquire a user info specific access token by not specifying any resource in a request to the token endpoint.'
However, I see this:
POST http://login.microsoftonline.com:443/common/oauth2/token HTTP/1.1
Host: login.microsoftonline.com:443
...
{"error":"invalid_resource","error_description":"AADSTS50001: Resource identifier is not provided.}

Related

Azure AD Bearer Token has wrong "aud" claims

I am trying to use AAD delegated permission Bearer tokens for a Visio VSTO addin to create SharePoint Online pages using CSOM. Initially I was able to get this working entering username / password following Modern Authentication with CSOM for Net Standard
However, I would like for the user to select an existing AAD account. When I attempt to use the following code the Bearer token "aud" claim is consistently set to "00000003-0000-0000-c000-000000000000" which is the Graph API. Whilst a ClientContext object is returned I am getting a HTTP 401 Unauthorized error when performing a page lookup.
The code is as follows
//
// Get Client App
//
var ClientApp = (PublicClientApplication)PublicClientApplicationBuilder.Create(<AAD App ID>)
.WithDefaultRedirectUri()
.WithTenantId(<AAD Tenant ID>)
.WithAuthority(AzureCloudInstance.AzurePublic, <AAD Tenant ID>)
.Build();
//
// Prompt for user to select preferred AAD account
// The returned JWT Bearer Token "aud" claim is 00000003-0000-0000-c000-000000000000
//
var Token = ClientApp.AcquireTokenInteractive(scopes)
.WithPrompt(Prompt.SelectAccount)
.WithParentActivityOrWindow(GetActiveWindow())
.ExecuteAsync()
.GetAwaiter()
.GetResult();
//
// Get client Context
//
var ClientContext = AuthenticationManager.GetAzureADAccessTokenAuthenticatedContext(<SharePoint Site URL>, Token.AccessToken);
//
// Using the Client Context to query the Site results in HTTP 401
//
ClientContext.Load(ClientContext.Web, p => p.Title, t => t.Description);
ClientContext.ExecuteQuery();
Looking at the code for the AuthenticationManager class in the above link I can see that the AAD Bearer request is passing the following resource request parameter to the SharePoint online URL:
var body = $"resource={resource}&client_id={clientId}&grant_type=password&username={HttpUtility.UrlEncode(username)}&password={HttpUtility.UrlEncode(password)}";
So it seems that AAD is setting the Bearer token "aud" claim based upon this parameter. However, when I try and add this parameter using 'WithExtraQueryParameters' I am getting the following error: "AADSTS901002: The 'resource' request parameter is not supported"
Ok, I figured out the problem. The scope needs to be prefixed with the resource:
string[] scopes = { "https://<domain>.sharepoint.com/AllSites.Write", "user.read" }
Then retrieve the token
this.Token = await ClientApp.AcquireTokenInteractive(scopes)
.WithPrompt(Prompt.SelectAccount)
.WithParentActivityOrWindow(GetActiveWindow())
.ExecuteAsync();

Easy Auth returns empty response for some people

I'm using the /.auth/me endpoint to get claims for the users.
I'm obtaining the Bearer token in order to authenticate to the endpoint.
The endpoint itself is on an Azure Function origin, so what I'm calling is https://azure_function_name.azurewebsites.net/.auth/me with the Authorization header set to Bearer (token)
This works but not for all people.
Some people get the following response from the /.auth/me endpoint:
[]
Why the /.auth/me endpoint returns a valid response for some tokens (people) and an empty response for other?
I am using OAuth 2.0 auth code grant(with a user login) to get the access token. And I can get the correct response with endpoint /.auth/me. I have tried both Member or Guest users in my tenant.
You can try to access https://azure_function_name.azurewebsites.net/.auth/me directly. You will get the response after logging in.
The reply url should be https://azure_function_name.azurewebsites.net/.auth/login/aad/callback

Microsoft Graph Admin Consent Flow Doesn't Contain Refresh Token

Is it possible to get refresh token also in the admin consent flow?
I've received access_token but not refresh_token even though I've included the offline_access permission in the delegated permissions.
to be more clear: I need to get to the users drive files (i.e get/update files) of the entire tenant (organization). therefore i'm requesting Application Permissions and Using the admin consent endpoint.
therefore I use the client_credentials grant in order to get the entire tenant access_token but unfortunately with no refresh_token in order to extend time of privileges of the tenant for more then 1 hour.
if i misuse the protocols above clarification will be highly appreciated
While Marc's answer is correct, I think the whole thing can be explained in a little more detail:
To get full access to a tenant (i.e. not just resources associated with the current consenting user), then you need to use the Admin Consent flow. However, unlike other flows in Graph's OAuth, you do not require a refresh_token to maintain access. Instead, you can simply request an access_token at any time once an admin has consented. Each access_token lasts 60 minutes.
Having first used other flows such as the Management API and Graph's Code Grant flow, this one confused me, but it's actually even simpler than those.
To get consent, simply direct the admin to the following URL:
https://login.microsoftonline.com/[Their Tenant ID]/adminconsent?client_id=[Your Client ID]&redirect_uri=[Your Redirect URI]
Your redirect URI will get a response with params:
?admin_consent=True&tenant=[Their Tenant ID]
Once you've received this confirmation, you can request an access_token at any time by sending a POST request with the following form fields:
client_id: [Your Client ID],
client_secret: [Your Client Secret],
scope: 'https://graph.microsoft.com/.default',
grant_type: 'client_credentials'
To the following URI:
https://login.microsoftonline.com/[Their Tenant ID]/oauth2/v2.0/token
The response will contain a new 60 minute access_token and you can simply call it again whenever required.
Refresh Tokens are only returned when both offline_access is requested and you are using the Authorization Code Grant.
More importantly, if you are receiving an access_token then you are not executing the Admin Consent workflow. Administrative Consent is only used for consenting to your application's scopes. The Admin Consent response does not contain an access_token, it only contains the Tenant ID (for the tenant that was consented) and a boolean that tells you if consent was granted as query parameters:
http://{return_uri}/?tenant=[tenant id]&admin_consent=[True/False]
If you are receiving an access_token then you are using either the Authorization Code, Client Credentials, or Implicit grants.
UPDATE:
There is no refresh token issued for Client Credentials, you simply request a new token from the /token endpoint as needed.

Obtain AzureAppProxyAccessCookie when I have a valid Azure AD JWT token

Some background info:
I'm working on a two-factor authentication solution for some API by using
Azure AD
encoded api key
I'm able to get a valid access token pogrammatically to be used as authorization bearer token on the header request. Unfortunately, the API expects the 2) encoded api key to be delivered through the authorizaton field, and as such, I'm expected to use the pass AAD auth through a cookie instead.
If I direct chrome to my api and log in normally while capturing the traffic, I see that the cookie AzureAppProxyAccessCookie is set.
If i do a curl GET request with this cookie against my api, the response is successful.
TLDR/Actual question:
How can I obtain a valid AzureAppProxyAccessCookie programmatically when I already am able to obtain a valid JWT token?

Azure AD openid connect not including token_type in response

I am attempting to convert over from the old Azure AD OpenId Connect to use the new Azure AD v2.0 endpoint as documented here: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols-oidc
When I attempt to request a token via the v2.0 token endpoint: https://login.microsoftonline.com/common/oauth2/v2.0/token
I get a response that only includes a 'token_id' field, and not a 'token_type', or any other fields. The library I am using to parse the response is nimbus.com library for openid and auth2. The OIDCTokenReponseParser throws an exception because the 'token_type' is missing from the response.
I have looked at the OpenID Connect Protocol specifications, and it says that a request to the token endpoint requires 'token_type', so it seems as though the response from the endpoint is invalid.
Has anyone run into this issue, and if so, how did you deal with it?
UPDATE 3/2/2018
My flow works with the old end point. I redirect the user here:
https://login.microsoftonline.com/common/oauth2/authorize?response_type=code&client_id={id}&redirect_uri={uri}&scope=openid+profile+email&state={state}
The user logs in, and they are redirected to my app, and code is provided via a query parameter.
I turn around and make this request:
https://login.microsoftonline.com/common/oauth2/token?code={code}&grant_type=authorization_code&client_secret={secret}
And I get response that looks like this.
{
"token_type": "Bearer",
"expires_in": "3599",
"ext_expires_in": "0",
"expires_on": "1520018953",
"access_token": "{token}",
"refresh_token": "{token}",
"id_token": "{token}"
}
I try to handle v2.0 version the same way. I redirect the user to:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=code&client_id={id}&redirect_uri={uri}&scope=openid+profile+email&state={state}
And after they sign in, they are redirected back to my app with the 'code' as a query parameter.
I then send this request:
https://login.microsoftonline.com/common/oauth2/v2.0/token?code={code}&grant_type=authorization_code&client_secret={secret}&redirect_uri={uri}&client_id={id}
But this is the response I get:
{
"id_token":"{token}"
}
The scopes you've requested can all be satisfied with the contents of the ID Token only. In your Auth Request, try including a scope that would indicate that you need an access token (e.g. https://graph.microsoft.com/User.Read), and the response will have the expected token_type and access_token.

Resources