SharePoint Rest API how to get Access Token? - sharepoint

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.

Related

InvalidAuthenticationToken error using msal and graph api from sharepoint

I am using the example msal-react to authenticate and consume sharepoint services using their graph api, create an application on AAD with delegated permissions.
I am assigning the scopes "https://mytenant.sharepoint.com/.default" and I get the following error code: "InvalidAuthenticationToken" message: "Access token validation failure. Invalid audience." check the token I get on the JWT.io page .
Thank you very much for your support
You are using the graph API to perform CRUD operations for SharePoint sites, so you should get an access token for the graph API instead of the SharePoint REST API.
So please change your scope to: https://graph.microsoft.com/.default.
I tried to reproduce the same in my environment via Postman and got below results:
I registered one SPA application and added SharePoint API permissions like below:
I generated access token via Postman with below parameters:
POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
client_id:appID
grant_type:authorization_code
scope: https://mytenant.sharepoint.com/.default
code:code
redirect_uri: https://jwt.ms
code_verifier:S256
Response:
When I decoded the token, it has SharePoint as audience and scp claim as below:
I got the same error as you when I used above token to call SharePoint from below graph API call:
GET https://graph.microsoft.com/v1.0/sites/<siteID>/lists
Response:
To resolve the error, assign Microsoft Graph API permissions for SharePoint like below:
Now, generate the access token again by changing the scope to https://graph.microsoft.com/.default as suggested by #Carl Zhao like below:
POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
client_id:appID
grant_type:authorization_code
scope: https://graph.microsoft.com/.default
code:code
redirect_uri: https://jwt.ms
code_verifier:S256
Response:
When I decoded the above token, I got Microsoft Graph as audience and scp claims are as below:
When I used above token to call SharePoint site lists from below graph API call, I got the results successfully like below:
GET https://graph.microsoft.com/v1.0/sites/<siteID>/lists
Response:
Note that, your token audience should be https://graph.microsoft.com while making graph calls and scp claim should contain Microsoft graph permissions.

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).

Azure Get All Organzations in multi tenants

In this article https://learn.microsoft.com/en-us/rest/api/resources/tenants/list I can get all the Tenants in my account. Now I want to get all the Organization in devops/vsts in each tenant or directory. Currently Im using this article https://learn.microsoft.com/en-us/rest/api/azure/devops/account/accounts/list?view=azure-devops-rest-5.0 and the token I get in the tenants is not working in getting all the organizations. Is theres a way to list all the organization in each tenant in my account? Thanks!
You can get the list via the below azure API call:
GET https://management.azure.com/tenants?api-version=2016-06-01
And for this API call to returns results correctly you need to gain access token and put it in the request header like that:
Authorization: Bearer access_token
And as shown in the documentation, you can gain the access_token from the below Identity end point as it's Implicit flow token:
Authorization URL: https://login.microsoftonline.com/common/oauth2/authorize
So the steps will be:
1- First make a call to:
https://login.microsoftonline.com/common/oauth2/authorize
With the appropriate parameters like the client_id and etc.
2- Gain access_token from the first step response.
3- Use this access_token to retrieve your talents list:
GET https://management.azure.com/tenants?api-version=2016-06-01
Authorization: Bearer access_token
And you can test this via postman or any curl based tool for verifying.

Microsoft Graph API Returning "Access Token Validation Error"

I've registered an Angular2 app with Microsoft that's completely client-side to access the Graph API. I've enabled Implicit Grant Flow and I'm able to obtain a JWT successfully after login and first-time authorization.
The URL fragment even says that it's a bearer token, like so:
http://localhost:4200/loginRedirect#access_token={JWT_TOKEN_HERE}&token_type=Bearer&expires_in=3600&session_state={state_guid}
My redirect to authenticate, for reference, looks like this:
window.location.href = "https://login.microsoftonline.com/common/oauth2/authorize?resource=" + encodeURIComponent('https://graph.windows.net') + "&response_type=token&client_id=" + this._config.clientId + "&redirect_uri=" + encodeURIComponent(this._config.redirectUri);
Despite including the acquired JWT in my the header of my Graph API request:
Authorization: Bearer {JWT_TOKEN_HERE}
I get a 401: Access Token Validation Error
I assumed that since I successfully retrieved that token it told me was a Bearer, it would've worked, but that doesn't appear to be the case.
Anyone know what I'm doing wrong?
Wrong resource URI. Azure AD Graph API is https://graph.windows.net.
Microsoft Graph API resource URI is https://graph.microsoft.com/, try it.
Azure AD Graph API is AAD's API, whereas Microsoft Graph API covers also Office 365 services. Confusing naming though.

Resources