What I'm trying to do is create a simple Microsoft Azure app that fetches all the contacts with Microsoft Graph. I THINK I understand how it should work, but seeing as I fail to actually make it work, I need some help.
I managed to fetch user data same as documented on their documentation site, but when following similar steps for contacts, I keep getting NoPermissionsInAccessToken.
My general workflow is to retrieve a token using:
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
?client_id={clientId}
&response_type=code
&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fdetail
&response_mode=query
&scope=openid+offline_access+profile+user.read+Mail.ReadWrite+Contacts.ReadWrite
With this I have acquired authorization code, refresh token and such. Now I plug that token into AuthorizationCodeProvider same as provided in example:
AuthorizationCodeProvider authProvider = new AuthorizationCodeProvider(
clientId,
Arrays.asList("openid", "offline_access", "profile", "user.read", "Mail.ReadWrite", "Contacts.ReadWrite"),
code,
"http://localhost:8080/detail",
NationalCloud.Global,
tenant,
secret);
IGraphServiceClient graphClient = GraphServiceClient
.builder()
.authenticationProvider(authProvider)
.buildClient();
IContactCollectionPage contacts = graphClient.me().contacts()
.buildRequest()
.get();
But when the application tries to execute get() from the last function it throws the following:
401 : Unauthorized
Strict-Transport-Security : max-age=31536000
Cache-Control : private
x-ms-ags-diagnostic : {"ServerInfo":{"DataCenter":"West Europe","Slice":"SliceC","Ring":"5","ScaleUnit":"000","RoleInstance":"AGSFE_IN_53"}}
client-request-id : e393d9d1-1eae-44b2-9956-2b97c0105b42
request-id : fecedee8-8b69-44b1-b300-5c9f71d3c427
Content-Length : 284
Date : Thu, 13 Feb 2020 13:12:27 GMT
Content-Type : application/json
{
"error": {
"code": "NoPermissionsInAccessToken",
"message": "The token contains no permissions, or permissions can not be understood.",
"innerError": {
"request-id": "fecedee8-8b69-44b1-b300-5c9f71d3c427",
"date": "2020-02-13T13:12:27"
}
}
}
As far as I know I have given the application all the necessary grants through portal.azure.com. Went to app registration, my application, API permissions, and added delegated Contacts.ReadWrite permission that is documented to be necessary.
Any idea what I can do to make this thing work?
When you call https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize it is returning an Authorization Code, not an Access Token. You need to exchange that Auth Code for an Access Token via https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token.
You can find step-by-step instructions for retrieving a token in the documentation.
Your app uses the authorization code received in the previous step to request an access token by sending a POST request to the /token endpoint.
Related
I am very new into this. Tried to get data from spotify. So tried the what they are provide but its not working. Getting bad request and in response its showing
{
"error": {
"status": 400,
"message": "Client credentials authentication not allowed"
}
}
URL : https://api.spotify.com/v1/me/following?type=artist (Get URL)
Provided Bearer token.
Also I want to understand that how can I pass user id here as if I need to get data for particular user.
Please help me on this.
From the docs (and messing around a bit), I found that the flow should look something like this:
Make a request to the /authorize endpoint with query params: cliend_id, redirect_uri, response_type and scopes (if you're just testing to get a token, use response_type: token)
You will be asked to log in and authorize the scopes (in this case it should be the scope allowing the client to read the user's artists)
In the redirect uri, there will be a token that you can use for the request
https://developer.spotify.com/documentation/general/guides/authorization/code-flow/
https://developer.spotify.com/documentation/general/guides/authorization/scopes/
I'm making a Java application to send Mail as any user in a Microsoft tenant, with Graph APIs, so I'm using the client credentials flow (no login, automatic send).
I've registered an app in Azure AD giving the following application permissions (not delegated), checking out the admin consent for every item:
Mail.Send
Mail.ReadWrite
User.Read.All
For semplicity, I've tried also with calls in Postman, but I have the same issue as in the Java app. I take for granted that I have got a valid access token (If I try with an invalid one, I get a 401: Unauthorized). The following is the decoded access token that I get from https://jwt.ms/, with all the scopes included:
...
"roles": [
"Mail.ReadWrite",
"User.Read.All",
"Mail.Send"
],
...
This is my code in Java:
String user = "/users/<my user id or my user principal name>";
UserRequestBuilder defaultUser = new UserRequestBuilder(graphClient.getServiceRoot() + user, graphClient, null);
//graphClient.me()
defaultUser
.sendMail(UserSendMailParameterSet
.newBuilder()
.withMessage(message)
.withSaveToSentItems(saveToSentItems)
.build())
.buildRequest()
.post();
I can't use the "me" target (me() method) because this is client credentials flow, so there isn't a logged user. I need to specify the sender in this way: /users/{id | userPrincipalName}/sendMail.
This is how the call in Postman is composed:
Method: POST
URL:
.https://graph.microsoft.com/v1.0/users/{my user id or my user principal name}/sendMail
AUTHORIZATION:
Bearer Token (my access token)
HEADERS:
Content-Type: application/json
BODY(JSON):
{
"recipient": <recipient email>,
"subject": "This is a test mail",
"from": <mail that created the tenant, app and access token>,
"text": "This is the messge body..."
}
That's the response from the server (in both Postman and Java app):
STATUS: 405: Method Not Allowed
BODY:
{
"error": {
"code": "Request_BadRequest",
"message": "Specified HTTP method is not allowed for the request target.",
"innerError": {
"date": "2022-08-05T07:17:34",
"request-id": "XXXXXXXX-6075-4d13-83ed-XXXXXXXXXXXX",
"client-request-id": "XXXXXXXX-6075-4d13-83ed-XXXXXXXXXXXX"
}
}
}
Note 1:
I got my user id and my user principal name also with a Postman call using my access token,
exploiting the User.Read.All permission, with the following call:
https://graph.microsoft.com/v1.0/users
That's the response:
...
"userPrincipalName": "XXXXXX_XXXXXX.XXX#EXT##sendClientCredMail.onmicrosoft.com",
"id": "XXXXXXXX-4457-4944-bb22-XXXXXXXXXXXX"
}
]
}
Note 2:
Note that if I use the "principal name" in the call, I get a 405, if I use the "id" instead I get a 404: Not Found
Thanks in advance for any help, I've been trying for hours!
SOLVED
As Optimal said in the comments, the issue was that the user didn't have a licensed mailbox.
When I assigned a "Microsoft 365 Business Premium" license to that user, my code worked fine.
Check the licenses both on portal.azure.com for assignments, and on admin.microsoft.com for the active mailbox
Kind regards
I have been following https://github.com/microsoftgraph/msgraph-sdk-java project for getting all the mails using Microsoft Graph API. This project works fine based on my changed configuration.
However, this follows OAuth authentication and I have to configure redirect url, and while running project, I got authentication code as query param on given url.
I stuck at two points :
How to by pass redirect_url concept, since my application is going to run in background. so, is there any way, I can auto capture this authentication code?
By trading authentication code, I receive access_token having 3600 expiry using below method.
OAuth2AccessToken mAccessToken = mOAuthService.getAccessToken(authCodeFromURL);
In above object, receiving below JSON, which does not have refresh token.
{
"token_type": "Bearer",
"scope": "Files.ReadWrite openid User.Read Mail.Send Mail.ReadWrite",
"expires_in": 3600,
"ext_expires_in": 3600,
"access_token": "encryptedCode",
"id_token": "encryptedCode"
}
I have tried to get the new access token with below method from SDK by using id_token, but it is not working, gives me invalid.
OAuth2AccessToken mAccessToken = mOAuthService.refreshAccessToken(idToken);
Invalid JSON :
{
"error": "invalid_grant",
"error_description": "AADSTS9002313: Invalid request. Request is malformed or invalid.\r\nTrace ID: 03690b71-4056\r\nCorrelation ID: b70a7b7b-963b-4cd6\r\nTimestamp: 2019-05-22 08:24:33Z",
"error_codes": [9002313],
"timestamp": "2019-05-22 08:24:33Z",
"trace_id": "03690b71-4056-49b9",
"correlation_id": "b70a7b7b-963b-4cd6"
}
What is id_token?
How can I refresh this access_token? Or Is there any other way/method to do it?
Kindly note, I am looking for solution with Java SDK.
I am testing the Microsoft Graph beta endpoint that sends invitations to guest users to join the tenant. The endpoint I am using is :
https://graph.microsoft.com/beta/invitations
Body:
{
"invitedUserEmailAddress": "abc#xyz.com",
"inviteRedirectUrl": "https://myDomain"
}
I am passing the bearer token in Authorization header that I got for the local admin user through the ADAL4J api. However, this call gives me a 401 Unauthorized error. Following is the response:
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token validation failure.",
"innerError": {
"request-id": "91f8129e-70cc-467d-a45b-9309e55788d6",
"date": "2017-02-10T08:46:09"
}
}
}
Any clue on how to get this request working? On Github I have gone through other discussions(eg) where users are facing the same issue.
The token sent was obtained with resource as "https://graph.windows.net". The expected resource/audience for Microsoft Graph API is "https://graph.microsoft.com". Update your application manifest to include Microsoft Graph as a resource and request the required permissions. Then request token with above mentioned resource/audience.
I am excatly in the same situation as #adarsh hegde. But I am targetting an azure B2C instead.
I can get the token for the windows graph (using resource "https://graph.windows.net"), and I am able to create users whithin my web app that is registered with the right permission.
What I did is to acquire token for graph.microsoft.com on the same time, but this token doesn't let me use invitations giving me the same error as you :
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token validation failure.",
"innerError": {
"request-id": "91f8129e-70cc-467d-a45b-9309e55788d6",
"date": "2017-02-10T08:46:09"
}
}
}
UPDATE:
So here are the steps that I've done so far:
ADB2C directroy
Web app with OpenID registered in there with required permissions to manage users in the AD following this link
When admin is logged in, the Web app in trusted mode is able to let him manage users (create/add/etc...)
Now what I want to use is the InvitationManager part of the MS graph (graph.microosoft.com) to be able to send invitation mail. can I redeem the code received in the OpenIdConnectAuthenticationNotifications to get access token for the MS graph? knowing that I already do that but for AD graph (graph.windows.net)
Thanks for the help
I am trying to retrieve user photo using outlook REST API(https://msdn.microsoft.com/en-us/office/office365/api/photo-rest-operations#UserphotooperationsGetphoto)
I got the access token following (https://msdn.microsoft.com/en-us/library/azure/dn645543.aspx)
but getting this error : any help?
HTTP/1.1 401 Unauthorized [Content-Length: 0, Server: Microsoft-IIS/8.0, request-id: 6925fcab-9021-4059-af4b-4cbf130faea7, X-CalculatedBETarget: CY1PR0401MB1388.namprd04.prod.outlook.com, X-BackEndHttpStatus: 401, Set-Cookie: exchangecookie=87cb2447eae9401c80a96c497dff06a9; expires=Sat, 22-Apr-2017 07:56:53 GMT; path=/; HttpOnly, x-ms-diagnostics: 2000001;reason="The access token is acquired using an authentication method that is too weak to allow access for this application. Presented auth strength was 1, required is 2.";error_category="invalid_token",
code looks something like this:
HttpClient httpclient = HttpClients.createDefault();
final String bearerToken = getBearerToken();
HttpGet request = new HttpGet("https://outlook.office.com/api/v2.0/me/photo/$value");
request.setHeader(javax.ws.rs.core.HttpHeaders.AUTHORIZATION, "Bearer " + bearerToken);
request.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
HttpResponse response = httpclient.execute(request);
return IOUtils.toByteArray(response.getEntity().getContent());
According to the error message. Instead of a client_secret in your request body, you need a client_assertion.
For more details, you can reference the blog Building Daemon or Service Apps with Office 365 Mail, Calendar, and Contacts APIs (OAuth2 client credential flow)
According to the API you call "https://outlook.office.com/api/v2.0/me/photo/$value". It seems that you only want to get the photo for the current login user; if so, you can use Authorization Code Grant Flow to get the token which will not require the client certificates.
UPDATE#1:
Can this be done programmatically/API way
As far as I know, the consent need the user's or admin's interactivity.
https://login.windows.net/common/oauth2/authorize?response_type=code&client_id={0}&resource={1}&redirect_uri={2}&prompt={3}
If you are developing a ASP.NET web application, you can reference the sample project O365-WebApp-MultiTenant.
BTW, when calling the API with app-token, you need to specify the user name.
e.g.
https://outlook.office.com/api/v2.0/users('user1#customdomain.onmicrosoft.com')/messages
UPDATE#2:
The 403 code when updating the photo using the app token is expected result.
As we can see from the figure above, updating the user photo requires the delegated permission "User.Read.Write". The app token does not have permission to update user's photo.