I can't get email or profile scopes for an Azure B2C application, nor can I call the OIDC UserInfo endpoint - azure

I'm finding Azure B2C really confusing. Currently I am using oauth2_proxy behind an nginx ingress controller in a test (single node) AKS kubernetes environment. I have made a slight change to oauth2_proxy to redirect upon error to chain Workflows together (like password recovery link etc.) and everything is working so far. I get an authorisation cookie from oath2_proxy and the ingress controller lets me through.
My next step is to work out what the username is, and maybe gather some more informaton. I think I can get some of the information in the id_token, but I am failing to see "email" and "preferred_username". Apparently these are only available if my token has the "email" and "profile" scopes, but I cannot work out how to get those scopes on my B2C App.
Currently I have a test application. In it's API permissions area I have a single "read" permission so that I have a resource to request to get an access_token. I also have "email", "offline_access", "openid", "profile" and "User.Read" permissions from "Microsoft Graph" - all permissions are granted by the admin on the API permissions screen.
The process I have been following up to now for testing is to run a signin workflow, selecting my API in the resources dropdown. I then copy the "Code" into a token request in postman, and then try both the "https://graph.microsoft.com/v1.0/me" and the "https://graph.microsoft.com/oidc/userinfo" endpoints with both the "id_token" and the "access_token". Both of these respond with "InvalidAuthenticationToken", message "Access token validation failure".
I had since noticed that my resources dropdown still only contains "read" and "openid" access rights, so I have been copying the "run userflow" url and inserting the scopes for "email", "offline_access", "openid" and "profile". I have also ensured that my call to the "token" endpoint contains these scopes. The response from the token endpoint only returns scopes "read offline_access openid", so "profile" and "email" are missing.
I don't know how to configure my app registration in B2C so that the "email" and "profile" scopes become available. Since "openid" appears in the resource drop down, I would expect "email" and "profile to turn up in there, but they don't. My token calls definitely show that the scopes that I need are not returned.
My workflow url looks as follows:
https://********.b2clogin.com/********.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1_signup_signin&client_id=********&nonce=defaultNonce&redirect_uri=https%3A%2F%2Fjwt.ms&scope=openid%20user.read%20email%20profile%20offline_access%20https%3A%2F%2F********.onmicrosoft.com%2Ftestapp%2Fread&response_type=code&prompt=login
My token call looks as follows (using the code value from the workflow):
https://********.b2clogin.com/********/b2c_1_signup_signin/oauth2/v2.0/token?grant_type=authorization_code&client_id=********&response_type=code&redirect_uri=https://jwt.ms&response_mode=query&scope=https://********.onmicrosoft.com/apptest/read openid offline_access email profile&code=******CODE FROM WORKFLOW CALLBACK******
Token response is like:
{
"access_token": "******BIG LONG BASE64******",
"id_token": "******BIG LONG BASE64******",
"token_type": "Bearer",
"not_before": 1591607270,
"expires_in": 3600,
"expires_on": 1591610870,
"resource": "********",
"id_token_expires_in": 3600,
"profile_info": "******BASE64******",
"scope": "https://********.onmicrosoft.com/testapp/read offline_access openid",
"refresh_token": "******BASE64******",
"refresh_token_expires_in": 1209600
}
OIDC endpoint call like this:
https://graph.microsoft.com/oidc/userinfo
HAS HEADERS
Content-Type: application/json
Authorization: Bearer ********BASE64 from access_token********
Any help would be appreciated. i.e. how do I return additional scopes + how do I call the OIDC UserInfo endpoint.
Thanks.

I struggled with a similar issue a while back, where I wanted my API to use the access token to look up user info. Azure AD does not work in a standards compliant way:
Calling User Info requires a separate graph token
You have to use a token exchange request to get the graph token
Here are some resources of mine which I think are related and will hopefully give you enough info to resolve your problem. I think right now you are getting the error from Step 14 of the blog post.
Token Exchange + User Info Lookup C# Code
Blog Post on Azure AD Settings related to Graph / User Info

Related

How to query the Sharepoint REST api (not the Graph api) using an Azure AD registered application?

I have a web application registered in Azure AD and have it working with the Graph API. But I would like to be able to instead query the Sharepoint REST API.
I have added the sharepoint delegated permission scope "AllSites.Read" to my application (in addition to the Graph API scopes that I was using before) and request this scope (in addition to the other delagated msgraph scopes) when I get the oauth token from the user. I successfully get the token, using https://login.microsoftonline.com/common/oauth2/v2.0 for the authorization/token calls, but am unable to make a successful query:
My query looks like client.get(f"https://{tenant}.sharepoint.com/_api/web/lists") where tenant is the tenant of the particular user who's token I am using.
The error I get looks like {'error_description': 'Invalid issuer or signature.'} with reason="Token contains invalid signature.";category="invalid_client"' in the header of the response.
I am able to query the Graph api, but would like to also be able to query the Sharepoint REST api, because the Graph api is is insufficient for my actual use case, which will be to get Sharepoint groups (Graph api does not give sharepoint groups when I ask for groups, only Office 365 and Azure AD groups).
Update:
The permissions I've set on the app:
I have not added any scopes in Expose API, I don't know if I need to. I did not need this part to have it working with Graph API.
Lastly I'll mention that in Postman, controlled environment purely with this as the request, with OAuth 2.0:
Auth URL: https://login.microsoftonline.com/common/oauth2/v2.0/authorize
Access Token URL: https://login.microsoftonline.com/common/oauth2/v2.0/token
client_id
client_secret
Scope: AllSites.Read
I get a token successfully, with all the roles, although it still doesn't give me access to https://<tenant>.sharepoint.com/_api/web/lists. I get the following error:
"error": {
"code": "-2147024891, System.UnauthorizedAccessException",
"message": {
"lang": "en-US",
"value": "Access denied. You do not have permission to perform this action or access this resource."
}
}
}
which admittedly is probably a step forward from the invalid client error I was getting before, but still quite stuck.
I was able to get this to work in Postman:
OAuth 2.0
Grant Type: Authorization Code
Auth URL: https://login.microsoftonline.com/common/oauth2/v2.0/authorize
Access Token URL: https://login.microsoftonline.com/common/oauth2/v2.0/token
Client ID: <client_id>
Client Secret: <client_secret>
Scope: https://<tenant>.sharepoint.com/AllSites.FullControl
The token I get back has all of the permissions that I set on the application, including the Graph API ones and the Sharepoint scopes that I did not request in the Scope parameter of the auth request:
"scp": "AllSites.FullControl AllSites.Read Directory.Read.All Files.Read.All Group.Read.All MyFiles.Read Sites.Read.All Sites.Search.All User.Read User.Read.All", which was a little surprising.
A key point was setting the tenant url in the scope so that the aud parameter in the token comes back for the right tenant. It was coming back before configured for the resourceAppId associated with the Graph permissions (00000003-0000-0000-c000-000000000000), rather than the Sharepoint permissions. This way, aud got set to https://<tenant>.sharepoint.com and I was able to access https://<tenant>.sharepoint.com/_api/web/lists.
You can try to get the acccess token in PostMan for a testing purpose.
Callback URL: https://www.getpostman.com/oauth2/callback
Auth URL : https://login.microsoftonline.com/common/oauth2/authorize?resource=https://<tenant_name>.sharepoint.com
Access Token URL : https://login.microsoftonline.com/common/oauth2/token
Client ID : <Application_ID>
Client Secret : <KEY>
Grant Type : Authorization Code
Will pop up a login window to sign in and then generate the access token and get the SharePoint groups:
Reference:
Use Postman and Azure AD to send REST request to SharePoint Online

Wrong access_token from AAD with OAuth2 flow

I am making OAuth 2.0 auth code authentication flow with multi-tenant application.
Here is my authorize url:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=my_id&prompt=consent&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauthorize&response_type=code&scope=openid+offline_access&state=17
It goes fine and I receive auth_code. Then I make request with this auth_code to token_url and receive a lot of information, like:
token_type
scope
id_token
access_token
refresh_token
expires_at
ext_expires_in
Seems fine to me, but when I make request on API with access_token like:
https://management.azure.com/subscriptions/my_sub_id/locations?api-version=2016-06-01
with headers:
Content-Type:
- application/json
Authorization:
- Bearer EwBQA8l6BAAURSN/FHlDW5xN74t6GzbtsBBeBUYAAV1IHgHb4dOWblzfd/YsSuFicAMDYbua17QivnAT9/pIaeKAg3uKsK5VGqWLzjMOUQrCpd7R1RAM6RkzI0u8e4rpO7DISG7qLso5H5+U1jb+38/j1urcwlXMMxhy83ZXmdpkLXpZV+vcOV...
It responds with 401 error
body:
encoding: UTF-8
string: '{"error":{"code":"InvalidAuthenticationToken","message":"The access token is invalid."}}'
To be honest I think something wrong with my access_token. It seems not like JWT for me. Documentation says it looks like:
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCEV1Q..."
But my access_token looks like:
"access_token": "EwBYA8l6BAAURSN/FHlDW5xN74t6GzbtsBBeBUYAAZDe7JE/MPLoAi+Fr+1Xxq5eBe5N9l8Q+c4QjkY5PGEzRnBpPe7+v6h+PLdh1cceBQx+/JsB2QCrYSCt7x/zGsQAhwoY/"
Is it fine?
Here is my permissions for application:
Permissions
The main issue you have here is that you have only asked for an access token for the scopes openid offline_access. The resulting access token will be for Microsoft Graph (https://graph.microsoft.com), not for the Azure REST API (https://management.azure.com).
To indicate you would like a token for a given API, the scope parameter in your authorization request should include the delegated permission you would like the app to have for the API. In the case of Azure REST API, there's only one delegated permission: user_impersonation. The identifier URI for the Azure REST API is https://management.azure.com, so the scope value you want to use is:
openid offline_access https://management.azure.com/user_impersonation
Two more important notes:
As you've discovered, you will not always be issued an access token as a JWT which you can decode peek at. The format of the access token is an agreement between the service which issued the token (Azure AD or Microsoft Accounts, in this case), and the service for which the token was issued (Microsoft Graph, in this example).
You should not always include prompt=consent. prompt=consent should only be used if you have already tried signing in the user without the user needs to be re-prompted for consent for a new permission.
If you simply include the required scopes in the scopes parameter, the Microsoft Identity platform will take care of figuring out if it needs to prompt for consent or not. If you always include prompt=consent, you will find that many organizations will be blocked from accessing your app, because they've disabled the ability for users to grant consent themselves (and this parameter specifically states that you require the user to be prompted again).

How to call azure graph api using postman

I am trying to call graph api to get user information. I am using postman to get the token first and then using that token trying to make a request to graph api
I get the token with below post request and with 4 key values for grant_type, client_id, client_secret and resource.
https://login.microsoftonline.com/{{tenantid}}/oauth2/token
The response is
{
"token_type": "Bearer",
"expires_in": "3600",
"ext_expires_in": "3600",
"expires_on": "1555583717",
"not_before": "1555579817",
"resource": "https://management.azure.com/",
"access_token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxNiIsIng1dCI6IkhCeGw5bUFlNmd4YXZDa2NvT1UyVEhzRE5hMCIsImtpZCI6IkhCeGw5bUFlNmd4YXZDa2NvT1UyVEhzRE5hMCJ9.yyyyyyyLTBjYjZmZDNiM2UwNCIsInRpZCI6IjM3NGY4MDI2LTdiNTQtNGEzYS1iODdkLTMyOGZhMjZlYzEwZCIsInV0aSI6ImVWTWdDbkU4QWtPVXY3bFQ2QlRSQUEiLCJ2ZXIiOiIxLjAifQ.kxHCm2oGsuUvlXbncXQe7Wb0l-ZENqqG9_P_co0SPdYA3GkhFKDi6sQ7OaaHeDs4S6kN0-Diw5qBOzmFipSA5EUorA7UDbJfiSVVlaEzLY3IX_4WSV4Exc-kLOaX0j7KgvsEQbc5TEk8e4dPfokG98gGPmhy19xLyV84lX1v6DzgXINzP8gPkGmqR_J7iVFQ3m-Y18dHlxDpqQMTKxvQGnrsa7rflyxGUwEwwFZJH8t5NRv_mjQOIQBuosfhMAH88l-J8zEmXWLFqEzFBBWrz9UxT6X-XxRQZW4WBSoHTKd3vuBcEo6kUclfe4G7COOvI4zG0-j10mmGziKlzjNVMw"
}
Then I use the token to make GET request
https://graph.windows.net/{{company}}/users/{{email}}?api-version=1.6
and header
Key Value
Authorization Bearer {{token}}
but it fails with this error
{
"odata.error": {
"code": "Authentication_MissingOrMalformed",
"message": {
"lang": "en",
"value": "Access Token missing or malformed."
}
}
}
What is the correct way to make a request to graph api ?
Updated answer according to your case
Okay I am showing the step from the beginning. Make sure you have complete following step exactly.
Step:1 : Application Registration
Go to your azure portal and click on azure active directory. Now click on App registrations and Enter a name for your app. Make sure you have select Web app / API as application type. Put any Sign on URL it does not have any impact though.
See the screen shot below:
Step:2 Application Configuration
Configure your application setting by clicking on settings option. Copy the Application Id which is your client ID. Generate your client_secret on Key menu. Now click on Required permission option and click on Add at new window. Choose Select an API choose Microsoft Graph Then Select it.
See the below screen shot
So your azure portal configuration is all set.
Step:3 Token Access Flow
For getting token I am using OAuth 2.0 Client Credentials Grant Flow. Let fire up POSTMAN Enter your token endpoint your like below:
https://login.microsoftonline.com/`YourTenantNameOrID`.onmicrosoft.com/oauth2/token
Enter following data in right format:
grant_type:client_credentials
client_id:Your Portal Application ID
client_secret:Your application Key
resource:https://graph.microsoft.com/
Note: I am using Microsoft Graph API so resource has chosen
//graph.microsoft.com/
See the screen shot for more details
Step: 4 Check Claims Of your Token
You can make sure your token contains required information by validating it claims on JWT. You can use https://jwt.io/ to validate your token.
See the picture of claims below:
Step:5 Access Your Microsoft Graph API Resource
Define your Microsoft Graph API resource URL
For example : https://graph.microsoft.com/v1.0/users
Select your API http verb
Select Your Token Type to Bearer Token
Enter your token on left token text box
You are done click send and check your response as expected. See the screen shot for details.
Request Format:
Response From API:
Note: Make sure you have resource access permission unless you would get access denied error.
For more information you could take a look here
If you have any more confusion feel free to ask in comment line. Thank you and Happy coding!

Get Azure AD Basic User Profile

I'm trying to get the users basic profile from Azure AD. I have a React Native app authenticating against a Native Azure AD App registration. The access_token I got from that request is used to authenticate against a Web app / Api. The user is shown the propper consent screen with the permissions I set in Azure AD.
Microsoft Graph API
Read all users' basic profiles
Sign in and read user profile
Windows Azure Active Directory
Read all users' basic profiles
Sign in and read user profile
(added both Graph API & AAD because I didn't know which one to use)
When I try and get the users profile through https://graph.microsoft.com/v1.0/users/me, with the access_token gotten from the previous request I get:
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token validation failure.",
"innerError": {
"request-id": "00cdb708-bcf8-4b33-af21-14a046b16533",
"date": "2018-09-02T18:28:59"
}
}
}
The resource in my initial authentication request is the Web App / API's app id, and I don't think having 2 resources is an option (?).
What am I doing wrong, and what should I do to fix it? Thanks.
According to your descriptions, I assume you want to get the users profile, but get the error shows an invalid token.
Based on my test, the request URL that you posted is not correct.
It should be 'https://graph.microsoft.com/v1.0/me' or 'https://graph.microsoft.com/v1.0/users/{id | userPrincipalName}'.
We can trouble shoot your problems as follows.
First, check request, if it has correct 'Authorization' field. This document shows that we need the Authorization field in the request headers.
Second, if you have added the Authorization field in the request headers, could you provide the main code that we can identify if problem is from there ?
While getting the access token add "resource" : "https://graph.microsoft.com/" and use that access token in header with Bearer than hit the url ---> https://graph.microsoft.com/me?api-version=1.6
Don't forget to add the resource while getting access token
Thank me later :P

Getting the access token for Microsoft Graph API

I'm trying to get the access token for the Microsoft Graph API in order to access a SharePoint document library. My application is a windows service, hence I'm following the procedure described here.
But when I try to get the access token, the response that I get doesn't have the scope value. Below is my response:
{
"token_type": "Bearer",
"expires_in": "3600",
"expires_on":"1492452559",
"not_before": "1492448659",
"resource": "https://graph.microsoft.com",
"access_token": "Token"
}
Because of this when I try to query the Graph API with this access token, I'm getting an error saying: Either scp or roles claim need to be present in the token
Can someone please help me on how to get this working? Thanks in advance.
That seems your client application hasn't set the appropriate app permissions when using client credential flow , below is an illustration of application permissions section in Azure AD classic portal. Please select appropriate permissions needed and retry :
And in addition , when using client credential flow to get the access token , you could check the roles claims in access token(that is the way to check the app permission, not in token response) , using a tool like http://jwt.calebb.net/ to decode the access token and check the app permissions :

Resources