Azure B2C ROPC flow (Web Api): Let Users reset their password - azure

I've just found out how to update the password of a signed-in user via Graph api in my Web Api. Now I need to send a user that is not signed-in an email with a new password so they can sign in and change their password.
How can I send an email to an User without a signed-in user (so no token)? And if that's not possible, how can I give users the ability to change their forgotten passwords in my Web API (ROPC flow)? Thank you very much!

I tried to reproduce the same in my environment and got below results:
I registered one application and added API permission like below:
Now I generated one access token using ROPC flow via Postman like below:
POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
client_id: <appID>
grant_type:password
scope: https://graph.microsoft.com/Directory.AccessAsUser.All
username:devi#sritenantb2c.onmicrosoft.com↵
password: xxxxxxxxxxx
client_secret:<secret>
Response:
Now, I used the above token in below graph call and changed password successfully like below:
POST https://graph.microsoft.com/beta/users/<userID>/changePassword
Content-type: application/json
{
"currentPassword": "xxxxxxxxxx",
"newPassword": "yyyyyyyyyy"
}
Response:
Reference:
How to reset and change the password using Microsoft graph API of Azure AD B2C users by AmanpreetSingh-MSFT

Related

User unauthorized though the token is correct

I'm trying to integrate D365FO with a third party application, I was able to do the proper setup and register my app, fetch the Token as shown below:
I used the resource as the link for D365FO at the development machine, which is https://usnconeboxax1aos.cloud.onebox.dynamics.com/ and read the D365FO data as shown below:
I want to change the login methid, so I do login on behalf of the user, using the password, so I Disabled thesecurirty details at Azure (based on this), as below:
And got teh token of the loged user successfult as below:
But once I tried fetching the same data which I was able to fetch before, I got 401 unauthorized, though I'm loggin in using the Admin account:
The error 401 Unauthorized usually occurs if you make calls to the resource with invalid audience.
When you generate the access token with scope as user.read openid profile offline_access, audience will be Microsoft Graph that won't work with D365FO.
I tried to reproduce the same in my environment via Postman and got below results:
I registered one Azure AD application and added same API permissions like below:
Now I generated tokens with grant type as password by including same parameters as you like below:
POST https://login.microsoftonline.com/organizations/oauth2/v2.0/token
client_id: <appID>
client_secret: <secret>
scope: user.read openid profile offline_access
grant_type: password
username: admin#xxxxxxxxx.onmicrosoft.com
password: xxxxxxxxxxx
Response:
You can decode the above access token by pasting it in jwt.ms to check the audience.
When I decoded the access token, I got aud claim as 00000003-0000-0000-c000-000000000000 (i.e, Microsoft Graph) like below:
If you use this token to read D365FO data, you will get 401 Unauthorized error as audience is invalid.
To resolve the error, you need to generate access token with resource value as base URL of your D365FO instance by making below changes:
POST https://login.microsoftonline.com/organizations/oauth2/token
client_id: <appID>
client_secret: <secret>
resource: <base URL of your D365FO instance without the trailing '/'>
grant_type: password
username: admin#xxxxxxxxx.onmicrosoft.com
password: xxxxxxxxxxx
In your case, value of resource parameter should be https://usnconeboxax1aos.cloud.onebox.dynamics.com
This token will have audience same as your D365FO root URL. To confirm that, you can decode it in jwt.ms. If you use this token to read D365FO data, it will work!
Reference:
Test services by using third-party utilities - Finance & Operations | Dynamics 365 | Microsoft

Replicate Postman Oauth 2.0 using Python

I have this Authorization request that works.
How can I replicate it in Python?
I am using an Azure AD to authenticate the access.
Since you are working with python, your case is a : Oauth2 login for SSR web applications with Microsoft
Goal
Get an access_token from interactive login using the oauth2 authorization code grant
Steps
Here I will list all the steps required to do it with any language
Create a web with session with at least these endpoints
/ : home page
/callback : server route or path able to receive query params like /callback?code=123456. This along with your base domain will be called redirect_uri. Sample : http://localhost:8080/callback or http://acme.com/callback
Create and configure an app in Azure Dev Console. Same process is in Google, Facebook, Linkedin, etc. As a result you should have a clientId, clientSecret and a redirect url
Create a simple web with classic session in which if user is not logged-in, redirect (302) to this url:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=foo&response_type=code&redirect_uri=foo&response_mode=query&scope=offline_access%20user.read%20mail.read
clientid and redirect_uri are important here and should be the same of previous step
After that, browser should redirect the user to the platform login
If user enters valid credentials and accepts the consent warning, Microsoft will perform another redirect (302) to the provided redirect_uri but with special value: The auth code
http://acme.com/callback?code=123456798
In the backend of /callback get the code and send it to this new endpoint
Add a client_id & client_secret parameters
Add a code parameter with the code sent by microsoft
Add a redirect_uri parameter with previously used and registered on azure. Sample http://acme.com/callback or http://localhost:8080/callback
Add a grant_type parameter with a value of authorization_code
Issue the HTTP POST request with content-type: application/x-www-form-urlencoded
You should get a response with the precious access_token:
{
token_type: 'Bearer',
scope: 'Mail.Read User.Read profile openid email',
expires_in: 5020,
ext_expires_in: 5020,
access_token: 'eyJ0oVlKhZHsvMhRydQ',
refresh_token: 's_Rcrqf6xMaWcPHJxRFwCQFkL_qUYqBLM71UN6'
}
You could do with this token, whatever you configured in azure. Sample: If you want to access to user calendar, profile, etc on behalf of the user, you should have registered this in the azure console. So the clientid is related to that and human user will be prompted with something like this
Libraries
There is some libraries provided by microsoft (c#, nodejs) which will save you a little work. Anyway the previous explanation are very detailed.
Advice
Read about oauth2 spec: https://oauth.net/2/
Read about oauth2 authorization code flow login before the implementation with python
https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow
https://github.com/msusdev/microsoft_identity_platform_dev/blob/main/presentations/auth_users_msalnet.md
Check this to understand how configure the azure web console: https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app
Check my gist https://gist.github.com/jrichardsz/5b8ba730978fce7a7c585007d3fd06b4

Azure B2C React SPA dose not providing access token

I am working on my first project of connecting Azure B2C with MERN App. I wanted to Sign In using Azure B2C and authorise my web API using the Access Token.
I configured everything and applied configurations to this sample React tutorial provide by their documentation.
The problem arises while calling the Web API. The Web API call are sending without any token. When I check the code, acquireTokenSilent function returning empty accessToken from response.
instance.acquireTokenSilent({
scopes: protectedResources.apiHello.scopes,
account: account
}).then(async (response) => {
console.log(response)
The Request is:
Even though I looked many forums and Microsoft technical forums, no answer is not working.
But what I noticed is, it is requesting for grant_type: authorization_code but am not seeing access token in the response. Posting here the API call, request and response.
The Response is producing id_token but not access token,
I gave grant permission in the SPA App permission for task.read scope. I tried everything but I am still receiving the access token as empty. How could I fix this issue?
I tried to reproduce the same in my environment and got below results:
I registered one Azure AD B2C application for app1 and added scopes(task.read) as below:
Now I created one SPA registration and added API permissions by granting consent like this:
I created Sign up and sign in policy and ran the user flow as below:
Please Check authentication and access token and id token:
I signed in as user it gave me auth code in address bar.
https://<tenant name >.b2clogin.com/<tenant name> .onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1_susi&client_id=<app id>&nonce=defaultNonce&redirect_uri=https://jwt.ms&scope=openid%20https%3A%2F%2F<tenant name>.onmicrosoft.com tasks.read&response_type=code&prompt=login&code_challenge_method=S256&code_challenge=<challenge paramater>
I generated the access token via Postman with commands like this:
POST https://tenant.b2clogin.com/tenant.onmicrosoft.com/policy/oauth2/v2.0/token
grant_type: authorization_code
client_id: SPA_appid
scope: https://tenant.onmicrosoft.com/app1/task.read
redirect_uri: redirect_uri
code: code
code_verifier: code_verifier
Postman
When I decode the token i getting scp in jwt .ms

For IMAP.AccessAsUser.All Scope ADSTS65001: The user or administrator has not consented to use the application

In my java web application I want to get access to user's mailbox by using jakarta mail. For that purpose I followed https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth for OAuth2 authorization code flow.
On Azure port I setup my app and added API permissions as below
Now user is redirecting to below authorize endpoint:
https://login.microsoftonline.com/5426ee07-9b73-4a9e-8075-395ab439c6fa/oauth2/v2.0/authorize?client_id=b6067ad9-7195-430b-a35d-97b7aa7beb8f&response_type=code&redirect_uri=http://localhost:8080/callback/microsoft&response_mode=query&scope=offline_access%20https%3A%2F%2Fgraph.microsoft.com%2FIMAP.AccessAsUser.All%20https%3A%2F%2Fgraph.microsoft.com%2FSMTP.Send
After entering credentials and accepting the consent redirect_uri gets hit with auth code. Based on that auth code I formed token endpoint URL and hitting it from server, the token endpoint is as follow:
URL: https://login.microsoftonline.com/5426ee07-9b73-4a9e-8075-395ab439c6fa/oauth2/v2.0/token
Form Data:
client_id=b6067ad9-7195-430b-a35d-97b7aa7beb8f
scope=offline_access%20https%3A%2F%2Foutlook.office.com%2FIMAP.AccessAsUser.All
redirect_uri=http://localhost:8080/callback/microsoft
grant_type=authorization_code
client_secret=QUs8Q~aboLBiopTezMTKwzQjIwWsFFXjc2kCRaRs (I know I have shared the secret)
code={code received from authorize end point}
Response to this post request comes as:
{"error":"invalid_grant","error_description":"AADSTS65001: The user or administrator has not consented to use the application with ID 'b6067ad9-7195-430b-a35d-97b7aa7beb8f' named 'Email Connector'. Send an interactive authorization request for this user and resource.\r\nTrace ID: dc008ced-e23f-4919-bd45-b7ae7c68b000\r\nCorrelation ID: 9b6ede03-3c05-4a78-8975-036a3cb20773\r\nTimestamp: 2022-06-07 19:51:30Z","error_codes":[65001],"timestamp":"2022-06-07 19:51:30Z","trace_id":"dc008ced-e23f-4919-bd45-b7ae7c68b000","correlation_id":"9b6ede03-3c05-4a78-8975-036a3cb20773","suberror":"consent_required"}
Here, I don't understand why the error is saying The user or administrator has not consented to use the application, user has accepted the consent after entering credentials on authorize end point. Event more If we look at the screenshot above admin has already given grant to access the directory.
I tried to reproduce the same scenario in my environment and got the same error as below:
To resolve the error, please check the authorize endpoint you are using to get the code.
Avoid using Microsoft graph API scopes while getting the code.
Replace it with the scope you are using to get access token like below:
https://login.microsoftonline.com/Your_TenantID/oauth2/v2.0/authorize?
client_id=Your_ClientID
&response_type=code
&redirect_uri=http://localhost:8080/callback/microsoft
&response_mode=query
&scope= offline_access https://outlook.office.com/IMAP.AccessAsUser.All
&state=12345
Get the code from the above authorization endpoint.
I got the access token successfully after modifying the endpoint like below:
To validate the access token decode it in jwt.io and check the aud and scp claims like below:

Microsoft Graph API - cannot refresh access token

I have registered a multitenant app at https://apps.dev.microsoft.com since the "admin consent" prompt wasn't available in the Azure AD apps. Admin consent is required for our app to retrieve info about users and their calendars.
I can provide admin consent from a completely different tenant than what this app is registered from and use the provided access token to retrieve all necessary information, however that obviously expires after an hour and we need offline access.
I have tried using the tenantId instead of 'common' in the https://login.windows.net/common/oauth2/token endpoint, however receive the same message as below.
The following is the data being submitted to the token endpoint in json format (converted within node to form encoded format before submitting):
{
grant_type: 'refresh_token',
client_id: 'e5c0d59d-b2c8-4916-99ac-3c06d942b3e3',
client_secret: '(redacted)',
refresh_token: '(redacted)',
scope: 'openid offline_access calendars.read user.read.all'
}
When I try to refresh the access token I receive an error:
{
"error":"invalid_grant",
"error_description":"AADSTS65001: The user or administrator has not consented to use the application with ID 'e5c0d59d-b2c8-4916-99ac-3c06d942b3e3'. Send an interactive authorization request for this user and resource.\r\nTrace ID: 2bffaa08-8c56-4872-8f9c-985417402e00\r\nCorrelation ID: c7653601-bf96-46c3-b1ff-4857fb25b7dc\r\nTimestamp: 2017-03-22 02:17:13Z",
"error_codes":[65001],
"timestamp":"2017-03-22 02:17:13Z",
"trace_id":"2bffaa08-8c56-4872-8f9c-985417402e00",
"correlation_id":"c7653601-bf96-46c3-b1ff-4857fb25b7dc"
}
This error occurs even when standard consent is used. I have also tried using the node-adal library instead of raw http requests which produces the exact same result.
I note that "offline_access" isn't a permission I am able to set within the MS apps portal, however I would guess the fact that I am getting a refresh token back means that I can refresh the access token?
For the record, the following is the node-adal code I used to see if I was doing something wrong:
var self = this;
var authenticationContext = new AuthenticationContext('https://login.windows.net/common');
authenticationContext.acquireTokenWithRefreshToken(
self.refreshToken,
self.clientId,
self.clientSecret,
'https://graph.microsoft.com/',
function(a) {
console.log(a);
}
);
Any help in getting this refresh process working is appreciated!
Please ensure that the tenant that you using for refreshing token is same as the tenant that you requesting for the access_token.
The refresh token request works well for me unless in the scenario of below:
register the app from protal using Microsoft account
user1 is in tenant1
add user1 as the external users to tenant2
request the access_token/refresh_token from tenant1(OK)
try to refresh the token using tenant1 in the request(OK)
try to refresh the token using tenant2 in the request(same error message)

Resources