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).
Related
I got SAML setup on my AD and I have the private and certificate PEMs along with the certificate and metadata and I want to know if it's possible to bypass the login from API? I'm developing a Node.JS API which I want to make requests to the server behind the SAML login but I need to bypass it with what I got.
Maybe a way to generate a token from Azure's API (to use as bearer authorization) would work like how you do it with OAuth?
I'm not asking for any other solution (like whitelisting etc.), I just need it to be token / API based
To bypass azure ad , you may chose for the On behalf flow.
For single-page apps (SPAs), here we pass an access token to a middle-tier confidential client to perform OBO flows instead.
This will only work, if the respective permissions (scope grants) are
already granted when you try to get an access token using the
on-behalf of flow.
Here API A authenticates to the Microsoft identity platform token
issuance endpoint and requests a token to access API B.
https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token
with grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
client_id=xxx
&client_secret=saxx1s
&scope=https://graph.microsoft.com/user.read+offline_access
&requested_token_use=on_behalf_of
Here we need to expose api and here I am giving user.read
And exposed api
The response has access token , refresh token
{
"token_type": "Bearer",
"scope": "https://graph.microsoft.com/user.read",
"expires_in": 3269,
"ext_expires_in": 0,
"access_token": "xx",
"refresh_token": "xxxx"
}
Please check Microsoft identity platform and OAuth2.0 On-Behalf-Of flow - Microsoft Entra | Microsoft Learn
Reference : how-to-use-azure-ad-access-token-to-bypass-microsoft-online-login
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
Just starting to work with SharePoint and Microsoft authentication and trying to get a SharePoint List into a JavaScript App. From Microsoft documentation, I need to use the following:
GET https://{site_url}/_api/web/lists/GetByTitle('List Title')
Authorization: "Bearer " + accessToken
Accept: "application/json;odata=verbose"
Have searched everywhere to find an definitive answer to how to obtain this accessToken. All the documentation I can find from Microsoft seem to be out of date. Does anyone know the current method to obtain an accessToken?
To call SharePoint specific APIs you need to get a SPO specific access token. You can "swap" an regular MS Graph refresh token for an SPO specific token by doing the following:
Get a delegated auth token from graph as you normally would
(https://learn.microsoft.com/en-us/graph/auth-v2-user)
Use the refresh_token you got and exchange it for an SPO access token by calling the auth endpoint again:
POST https://login.microsoftonline.com/{{tenantName}}/oauth2/v2.0/token
With the following form data:
client_id=<APP ID>
client_secret=<APP SECRET>
refresh_token=<REFRESH TOKEN FROM ABOVE>
grant_type=refresh_token
scope=https://<YOUR TENANT NAME>.sharepoint.com/Sites.Read.All
Take the access token and call the SPO API
You must ensure your app is registered with the correct permissions. In the case above the app must have Sites.Read.All for example.
You could refer to this article to get access token:
https://global-sharepoint.com/sharepoint-online/in-4-steps-access-sharepoint-online-data-using-postman-tool/
Post https://accounts.accesscontrol.windows.net/<Tenant ID>/tokens/OAuth/2
Body:
grant_type client_credentials
client_id <Client ID>
client_secret <Client Secret>
resource 00000003-0000-0ff1-ce00-000000000000/<tenant>.sharepoint.com#<Tenant ID>
My test result:
There is not much documentation for SP API, but it still works. You may follow documentation to get token for Graph API by whatever type of authentication is suitable for your scenario, but instead of passing scopes for Graph API (which is "https://graph.microsoft.com/.default"), you should pass scopes for Sharepoint API which is "https://{your tenant name}.sharepoint.com/.default"
".default" will provide you the access with all permissions which was assigned in Azure AD - so also make sure, that Azure admin has granted you required API permissions for SharePoint API.
This will also work for MSAL.
I'm trying to get a subscription created with the callRecord resource (https://learn.microsoft.com/en-us/graph/api/subscription-post-subscriptions?view=graph-rest-beta&tabs=http)
In the app registration section of the Azure portal, I've created a multi-tenant app with a client secret. That app has permissions for application-level "CallRecords.Read.All" as well as the default delegated "User.Read". The statuses also have a green checkbox for being granted against my organization by an admin.
I am able to get an access token with the following HTTP POST request to https://login.microsoftonline.com/common/oauth2/v2.0/token:
grant_type:authorization_code
scope:https://graph.microsoft.com/.default
client_secret:<client_secret>
client_id:<client_id>
code:<code>
redirect_uri:http://localhost:3000
However, that token is not able to generate a subscription to my callRecord resource. I get a response with this message: "Operation: Create; Exception: [Status Code: Forbidden; Reason: The request is not authorized for this user or application.]"
The message suggests that the app has not been granted admin-level authorization, but in fact it has. This used to work for me. I'm wondering if there has been a regression on the MS Graph side.
Further, when I examine the JWT, I see that the scope is "User.Read profile openid email". There is no mention of the application-level permission (specifically, CallRecords.Read.All)
Thanks.
Because when you use the auth code flow, just the Delegated permission will take effect. So even if you grant the Application permission, the token you got will not include the permission.
From the doc, to call this API Get callRecord, just the Application permission is supported.
To get the token which include the permission, your option is to use the client credential flow.
Note: You need to use <tenant-id> instead of common in this flow.
POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token
client_id=xxxxxxx
&scope=https://graph.microsoft.com/.default
&client_secret=xxxxxxx
&grant_type=client_credentials
Decode the token in https://jwt.io, the roles includes the CallRecords.Read.All permission:
Our web aap is authenticating with the Azure AD via SAML2.0 similar to this.
In return we get SAML assertion(SAML token).
But when the user who logs in have more then 150+ groups the response doesn't contain the group information(so that token size doesn’t exceed HTTP header size limits. More info on this)
But what it return is a Graph Api to be hit to get the group information something like https://graph.windows.net/{tenant id}/users/{user id}/getMemberObject.
By going through this
I understand that I need to attach a Auth bearer token with the http request to hit the graph api successfully.
My problem is how do I get the Auth bearer token?
How can I use the SAML token to get the Auth bearer token?
Other useful link - link1 link2
I've only used the non SAML graph API using the ADAL libraries but from the docs it appears the NameID seems to be the basis for requesting an access token for the Graph API:
<Subject>
<NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">m_H3naDei2LNxUmEcWd0BZlNi_jVET1pMLR6iQSuYmo</NameID>
<SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer" />
</Subject>
From this post,
"Here the Client gets a SAML bearer assertion from the SAML Identity
Provider then requests an access token from the Authorisation Server
using the SAML bearer assertion as proof of identity"
and this article states the entire Assertion is used to get the access token, where you:
encode the whole assertion by using base64url encoding before adding
it as part of the POST request
It appears that exchanging a SAML token for a Graph access token is only supported for AD FS, not Azure AD. As per:
This scenario works only when AD FS is the federated identity provider that issued the original SAMLv1 token. You cannot exchange a SAMLv2 token issued by Azure AD for a Microsoft Graph access token.
Source: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-saml-bearer-assertion.
In general, you have to add the OIDC/OAuth stack to your app. As I understand it, this is in addition to your existing SAML authentication implementation. See: https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-token-exchange-saml-oauth