I am coding against the Microsoft Graph API and I am trying to proof out the ability to generate an OAuth Token. I am using Postman and have my application hosted on Azure Active Directory. I am running into an issue in Postman when trying to pass in the correct Scopes - I am trying to pass in User.read however, Postman is not generating a Token.
My Settings:
Auth URL: https://login.windows.net/{my_tenent}/oauth2/authorize
Access URL: https://login.windows.net/{my_tenent}/oauth2/token
Scope: User.readAll
Are these the correct values to be passing in to generate an OAuth Token?
It sounds like you're mixing a bit of v1 and v2 endpoints here. I've written up a Microsoft v2 Endpoint Primer that might help you out here.
The URI for authentication with v2 should be https://login.microsoftonline.com/common/oauth2/v2.0/ rather than https://login.windows.net/{my_tenent}/oauth2/authorize.
When requesting scopes with Graph, be sure and use the full URI and not just the scope name itself. For example, user.read should be requested as https://graph.microsoft.com/user.read. Multiple scopes are space delimited so requesting user.read and mail.read would be formatted as "https://graph.microsoft.com/mail.read https://graph.microsoft.com/user.read.
If you would prefer to use the v1 Endpoint, you do not request scopes as part of the OAUTH workflow. With v1, scopes are defined in Azure Active Directory when you register the Application.
If you're not sure which to use, take a look at Deciding between the Azure AD and Azure AD v2.0 endpoints. In general, I tend to recommend v2 as it will eventually replace the legacy v1 implementation. There are however some older APIs (EWS, SfB, etc) that only support v1 at the moment so there are cases where your choice is made for you.
Did you make sure to set up your application to request permissions to the Microsoft Graph?
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications
The "permissions to other applications" section. You must statically select the scopes you want your application to call Microsoft Graph with, unless you are using the V2 endpoint which supports dynamic consent.
Let me know if this helps!
I fought with this same issue for nearly a day before finally figuring it out. These are the settings that work for me:
Token Name: [anything you want]
Auth Url: https://login.windows.net/common/oauth2/authorize?resource=https://graph.microsoft.com
Access Token URL: https://login.windows.net/common/oauth2/token?resource=https://outlook.office365.com/ (although, I don't think the refresh works)
Client ID: [your app's client id]
Client Secret: [your app's client secret]
Scope: I have a bunch of scopes in here, but they seem to be ignored. Scopes should be set in the app console
Grant Type: Authorization Code
Check "Request access token locally"
If everything works, you should get the login screen when you click "Request Token"
Related
I got a console app that needs to support two flows, authenticating against AAD to talk to a web api:
for regular usage by humans, it needs to support interactive login
for usage by a CI/CD pipeline it needs to support client-credentials.
The interactive flow works perfectly, but the client-credentials flow is giving me problems with the requested scope.
I'm using the latest Microsoft.Identity* nuget packages.
When I construct the scope for the webapi like I do for the interactive flow, I get an error message telling me that for client-credentials flows I need to append ./default. Okay, fair enough, I also found documentation for this, so I append ./default. But when I do that, I get another error message telling me
The resource principal named api:///access_as_user was not found in the tenant named .
There are two problems with this error message:
the resource principal quoted definitely exists - also, I couldn't login interactively if it didn't, but as mentioned, interactive login works just fine
it says api://<webApiAppId>/access_as_user, not api://<webApiAppId>/access_as_user/.default, despite my appending that
My next though was: well, maybe the problem is that the app registration used for the client-credentials flow doesn't have permissions on the web-api. But it does.
So now I've run out of ideas. Hopefully, someone here can help.
To make everything a bit clearer, let me list the app regs involved:
A. Web Api
Was setup via the VS Wizard/dotnet-msidentity tool
has a few App Roles defined
exposes a single API api://<itsownAppId>/access_as_user
B. Interactive Login
manually created
redirect URI for localhost
API Permissions: added WebApi | access_as_user as delegated
C. Non-interactive login/Service Principal
setup manually
is used also for other things by the CI/CD pipeline
has a ClientSecret defined
API Permissions: added WebApi | access_as_user with 2 of the app roles defined for A
has other API Permissions that have nothing to do with this here (for Graph)
granted admin consent for all permissions
The code I use to authenticate is (for the confidential flow):
ConfidentialClientApplicationBuilder.Create(_configuration.ApplicationId)
.WithTenantId(_configuration.Directory)
.WithLogging(Log, LogLevel.Error)
.WithClientSecret(_configuration.ClientSecret)
.Build()
.AcquireTokenForClient(_configuration.Scopes)
.ExecuteAsync();
where the values of _configuration are:
ApplicationId: the appId from app registration C
Directory: the name of my AAD tenant
ClientSecret: the secret from app registration C
Scopes: array of openid, profile and api://<appIdOfWebApiFromC>/access_as_user/.default
So, it turns out that the documentation for appending ./default is not quite clear enough:.You are not meant to append it to the scope, just to the "resource id". And with resource id they mean the "api://" parts without the name of the permission.
So where you normally request api://<webApiAppId>/access_as_user, for the client-credentials flow you have to request api://<webApiAppId>/.default
According to this official Microsoft document (and the documents referenced there) URIs using login.microsoftonline.com/myTenant/.. must be replaced by myTenant.b2clogin.com/mytenantId/..
For the interactive login with MSAL to get an ID token this works fine for me. But I can not figure out which URI to use with IConfidentialClientApplication and using a secret. I'm using MSAL 4.18 in a C# Windows application.
The following code works fine using login.microsoftonline.com.
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder
.Create(clientId)
// how must this URL look like when using b2clogin.com
.WithAuthority("https://login.microsoftonline.com/*MyTenant*.onmicrosoft.com/v2.0")
.WithClientSecret(secret)
.Build();
AuthenticationResult authenticationResult = await app
.AcquireTokenForClient(scopeArray)
.ExecuteAsync();
Whatever b2clogin.com URI I use (e.g. https://*myTenant*.b2clogin.com/*myTenantId*/v2.0) I get back an AADSTS50049: Unknown or invalid instance. response.
What am I missing? Can I continue to use login.microsoftonline.com for this case?
(This answer comes with a bit of twists, so please read till end :))
You should not generally continue to use login.microsoftonline.com for B2C, it will be retired on December 4, 2020.
Authority should be in format https://{your-tenant-name}.b2clogin.com/tfp/{your-tenant-ID}/{policyname} or https://{your-tenant-name}.b2clogin.com/tfp/{your-tenant-name}.onmicrosoft.com/{policyname}
Also, you should be using .WithB2CAuthority, not .WithAuthority for B2C in code for client setup (but there is a catch here for your case since it's Client Credential Grant which is in the later part of the answer).
Example code (though the example uses public client, in your case it's confidential client, just referring it for authority reference).
For details, refer this.
But since you are using Client Credential Grant Flow using client id and secret, it's not directly supported in B2C as documented here.
Although the OAuth 2.0 client credentials grant flow is not currently
directly supported by the Azure AD B2C authentication service, you can
set up client credential flow using Azure AD and the Microsoft
identity platform /token endpoint for an application in your Azure AD
B2C tenant. An Azure AD B2C tenant shares some functionality with
Azure AD enterprise tenants.
In summary, you can not use B2C directly for Client Credential Grant and workaround requires to use regular common enterprise AAD backend of B2C. So b2clogin.com part would not be applicable for this workaround. That mean only for this particular Client Credential Flow case, you should be continuing with login.microsoftonline.com since you are not actually using B2C in true sense for this.
I have a desktop app which uses ADAL for authentication, this app make requests to an API on the API Management azure service. After migrating the code to use MSAL, the API Management returns 401 saying that my token is invalid. The only difference that I see spying the requests is that ADAL makes a request to this endpoint /tenantID/oauth2/token and MSAL /tenantID/oauth2/v2.0/token.
In my API Management I have this policy:
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid. AAD" require-expiration-time="false">
<openid-config url="https://login.microsoftonline.com/tenantID/.well-known/openid-configuration" />
</validate-jwt>
I tried to change the well known url to v2.0 endpoint but get the same error. How can I validate the token using MSAL?
From the Note in the doc, when changing the well known url to v2.0, you may need to use common instead of tenantID.
<openid-config url="https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration" />
Also, make sure you have done the step 10 in this link correctly:
If you use v2 endpoints, use the scope you created for the backend-app
in the Default scope field. Also, make sure to set the value for
the accessTokenAcceptedVersion property to 2 in your
application manifest.
I'm writing a c# program right now that tries to authenticate with Azure to make a generic http request. I finally got the code working and I wanted to test the features but for every request I make I get the following error code in response:
{"error":{"code": "AuthorizationFailed", "message":"The client "(id of the app I registered in AzureAD)" with object id "(same value as before)" does not have authorization to perform action 'Microsoft.Authorization/roleAssignments/read' over scope '/subscriptions/(mysubscriptionid)'."}}.
The thing is ... The account I use to set everything up is a global admin. I checked every permission box in AzureAD I could find...
(that's 8 Application Permissions and 9 Delegated permissions in the Windows Azure Active Directory API and 1 delegated Permission in the Windows Azure Service Management API, though I don't know why there aren't more possible permissions for Azure Service Management)
the relevant code is rather basic but it works so I don't feel like I need post it, I'll just say that I obtain the Token using Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenAsync() with
authorityUri = "https://login.windows.net/(mytenantid)",
string resourceUri = "https://management.azure.com/";
AuthenticationContext authContext = new AuthenticationContext(authorityUri);
var res = authContext.AcquireTokenAsync(resourceUri, new
ClientCredential(clientId,clientSecret));
return res.Result;
and make the Request to
https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Authorization/roleAssignments?api-version=2016-03-01&$filter=atScope()
(as an example, this one is supposed to call the roles).
Tried several different types of GET Requests to different URIs, all give similar errors.
I'm thinking it might not be an issue with the code but a setting in the AzurePortal but everything I found there seems set up right (or rather "universal access").
According to your description, you forget to grant your service principal. You could add it on Azure Portal. You could grant Contributor or Owner role to it.
Please refer to this link:Assign application to role.
I have been told to raise a question about Azure AD Graph Api here instead of raising it as an issue for the corresponding GitHub sample repository, I hope Azure Graph API team monitors SO and can help us with this github sample issue
Some extra context for the problem:
We are using Microsoft.Azure.ActiveDirectory.GraphClient nuget to create and manage users in our Azure AD test tenant. Following this sample application
we can create and update users in Azure AD via Graph API. That was fine until some moment which happened about 2-3 days ago (not sure about the exact moment, we discovered the problem on Tuesday morning AU time. Last successful run was on Friday last week). It was 100% working code and to confirm that it's not our code - I ran through sample application again - it's broken now too. I've tested it with the latest GraphClient v2.1.0 and original one from sample app which is - v2.0.6
To simplify testing of the problem I've made a LINQ based sample with some secrets redacted ( you need to follow console app sample guide to put in your values if you want to run it, instead of original sample app)
Also here is the Fiddle captures (redacted) of
Authentication request-response (client-request-id: 88b2bbbd-94cd-498d-a147-caad05e16eb7)
User Creation failing Attempt
Few things to note in the fiddler captures - Azure AD Graph API doesn't return refresh token along with access token:
{"expires_in":"3599","token_type":"Bearer","scope":"UserProfile.Read",
"expires_on":"1441183928","not_before":"1441180028","resource":"https://graph.windows.net",
"access_token":"TOKEN WAS HERE"}
I can see the issue with the scope string here, but we are not setting any explict scope in GraphClient when calling for token as per Sample app ( and this code was fine before, as I mentioned early)
User creation response is clear in terms of what happens and why it happens
{"odata.error":
{"code":"Authorization_RequestDenied","message":
{"lang":"en","value":"Insufficient privileges to complete the operation."}
}
}
But it's not clear how to ask for extra permission scopes through any of these AuthenticationContext.AcquireToken Method overloads
Also it's strange that the very same code was fully functional before and is broken now, after some mysterious change?
So I have few questions:
How to add extra scope permissions in GraphClient library to get Graph API token with User Modification enabled. This is probably a band aid fix of the problem.
It looks like Azure AD tries to manage permissions for client apps in the portal. But there is no extra permissions for Native Client type of application. How can I explicitly update app permissions so the existing code can work again. Is it possible at all ?
Can anyone recommend other libraries to interact with GraphAPI, which allow the consumer to explicitly specify scope for the requested token ?
================Update================
Yes, I saw that consent flow documentation. Chasing the issue I've created new Azure AD tenant, added brand new application and added all possible rights, including all available application and delegation ones:
now it looks like this. I also
I can get a token with long list of scopes, e.g.
Directory.AccessAsUser.All
Directory.Read
Directory.Write
User.Read
User.ReadWrite
User.Read.All
User.ReadBasic.All
User.ReadWrite.All
user_impersonation
UserProfile.Read
--cut unrelated scopes--
But it still gives me 403 :
{"odata.error":
{"code":"Authorization_RequestDenied","message":
{"lang":"en","value":"Insufficient privileges to complete the operation."}
}
}
One thing worth to note - in the scope list there is no Directory.ReadWrite.All
But here docs says :
Directory.ReadWrite.All : Read and write directory data
================Update================
PS: Some technical request info for Azure AD engineers:
Authentication request-response has client-request-id: 88b2bbbd-94cd-498d-a147-caad05e16eb7.
Failed Graph call has client-request-id: 882f3918-0ddd-40fe-a558-866997e32b46 in response only
The issue here is that you have not properly configured your application to request the correct permissions to the Graph API.
To do this, you must go into the Azure Management Portal and configure your 'permissions to other applications' to include the scopes your app needs to be able to read/write to the directory.
We have some documentation here which should help you:
https://msdn.microsoft.com/en-us/library/azure/dn132599.aspx (Describes the consent flow)
https://msdn.microsoft.com/Library/Azure/Ad/Graph/api/graph-api-permission-scopes (describes the specific permissions that the graph API exposes that your application will need to request)
I hope this helps!