Access Web API(Nodejs) using ROPC Azure B2C flow (Without browser login) - node.js

I have Web API which is an NodeJs code. In Web API we have protect API using (passport.authenticate('oauth-bearer', {session: false}).
When generating token using ROPC app in postman, Access token is generated but at the time of authorization
var bearerStrategy = new BearerStrategy(options,
function (token, done) {
console.log(options);
console.log(token);
// Send user info using the second argument
done(null, {}, token);
}
);
This will return unauthorized.
I have added scope and configure Native and Web API as per document.

This issue was solved by #Sruthi comment, add it as the answer to close the question:
For login.microsoftonline.com, it is generally used to perform a
login request for Azure ad tenants to obtain tokens. For b2c
tenants, you need to use tenant-name.b2clogin.com to perform the
request.
Use ROPC flow to get access token:
POST https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/B2C_1_ROPC_Auth/oauth2/v2.0/token
username=<username>
&password=<Passxword>
&grant_type=password
&scope=openid+app_id+offline_access
&client_id=<client_id>
&response_type=token+id_token

(Moving from comments to Answer).
You can get access token using curl for ROPC curl -X POST -d "client_id=Clientid&scope=openid+appid+offline_access&grant_type=password&username=username&password=password&response_type=token" https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/B2C_1_ROPC_Auth/oauth2/v2.0/token'
As you are using old origin URL which is login.microsoftonline.com should no longer refer to your applications and APIs. Instead, use b2clogin.com for all new applications, and migrate existing applications from login.microsoftonline.com to b2clogin.com. Please refer to the official document

Related

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

Getting Error AADB2C99067 when trying to request access token from Azure B2C

I have an Azure AD B2C tenant setup with an Angular app on the front-end using Authorization Code Flow with PKCE and a back-end api. Everything is working fine. I now have a need to allow the user to access certain pages on the front-end anonymously. I would prefer to still protect the apis these pages will call using the same access token.
I have followed the article here to set up Client Credentials flow. I am able to get an access token successfully using Postman and use it to call my back-end apis fine. However, when I try to do the same from the Angular app, I get the following error:
{"error":"invalid_request","error_description":"AADB2C99067: Public Client XXXXX-XXXXXX is not supported for Client Credentials Grant Flow\r\nCorrelation ID: 2b3346ef-1828-4900-b890-06cdb8e0bb52\r\nTimestamp: 2022-07-28 04:12:21Z\r\n"}
Below is the code snippet I am using in Angular to retrieve the access token.
const urlencoded = new URLSearchParams();
urlencoded.set('grant_type', 'client_credentials');
urlencoded.set('client_id', '<clientid>');
urlencoded.set('client_secret', '<clientsecret>');
urlencoded.set('scope', '<scope>');
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }),
};
const url = 'https://<b2ctenant>.b2clogin.com/<b2ctenant>.onmicrosoft.com/<customPolicy>/oauth2/v2.0/token';
return this.httpClient.post(url, urlencoded, httpOptions);
Any ideas what could be missing?
Thanks!
Though azureadb2c supports client_credential flow.One may not use them with SPA apps.
This scenario is not supported by MSAL.js. Client credential flow/ grant type will not work in SPAs(Angular) because browsers cannot securely keep client secrets.
As they may end up in the browser, visible to everyone and to attackers that load them.
Note:As the application's own credentials itself are being used, they must be kept safe - never publish that credential in your source
code
If you are using it for web app , please make sure to select the platform as web or change the reply url type to be web.
"replyUrlsWithType": [
{
"url": "https......",
"type": "Web"
},
]
Please refer :
Configure authentication in a sample Angular SPA by using Azure
Active Directory B2C | Microsoft Docs
OAuth 2.0 client credentials flow on the Microsoft identity platform- Microsoft Entra | Microsoft Docs

Getting access denied when accessing Azure Web App via token

We are testing locking down an API hosted on Azure Web Apps by using the built-in Azure Web App Authentication/Authorization with Azure Active Directory.
We are calling POST https://login.microsoftonline.com/{tenantIDhere}/oauth2/v2.0/token with the following parameters in Postman:
grant_type: password
client_id: {ID}
username: {username}#{tenenat}.onmicrosoft.com
password: {password}
scope: https://{webappname}.azurewebsites.net/.default
client_secret: {secret}
Below is the response I get:
"token_type":"Bearer","scope":"https://{webappname}.azurewebsites.net/user_impersonation https://{webappname}.azurewebsites.net/.default","expires_in":3599,"ext_expires_in":3599,"access_token":"{TOKEN HERE}"}
So I take that token and try and access the webpage by passing the token in the header and I get the below error using POST:
https://{webappname}.azurewebsites.net/api/url
Authorization: Bearer {TOKEN HERE}
Response (401 Unauthorized)
You do not have permission to view this directory or page.
I have spent days trying everything I can find. What am I missing?? As soon as I turn off authorization needed for the web app, I get the expected result. But using the grant_type: password, I CANNOT get in! I have a feeling its related to the scope, but I cannot find documentation on what I need here for this. Any ideas?
The user is able to manually login to the webpage and pull the data, so it is not a permission issue. It has something to do with the token I believe.
If you are using v2.0 endpoint, the scope should be {your_client_id}/.default. Replace https://{webappname}.azurewebsites.net with the client id/application id for your API app in Azure AD.
Edit:
As Wayne said, you could also set scope as {your_client_id}/User.Read to get access token.

Firebase REST auth when creating token with node.js admin sdk

I know this issue was asked a lot here, but I still cannot seem to find the exact answer that can solve my problem.
I wish to access Firebase using REST calls, by adding an access_token param.
The access_token is created using the Node.js Admin SDK, using the following code:
var admin = require("firebase-admin");
var serviceAccount = require("./pk.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://XXX.firebaseio.com"
});
var uid = "1234";
admin.auth().createCustomToken(uid)
.then(function(customToken) {
// Send token back to client
console.log("Token: "+customToken);
})
.catch(function(error) {
console.log("Error creating custom token:", error);
});
The problem is that if I take the token created from Node.js and use it my REST call, I get an Unauthorized request error.
I have read in some questions that people added the scope param when issuing the token, but have not found a way to do that with Node.js Admin SDK.
Google's docs are not so detailed with this issue. Any idea what I might try to resolve this one?
The token you are using to authenticate to the Firebase REST API is not the correct type of token. You are using a Firebase Auth custom token, which can only be used to authenticate one of the Firebase client SDKs via the signInWithCustomToken() method as explained in Sign in using custom tokens on clients.
In order to authenticate to the Firebase REST API, you have two options: Firebase ID tokens (for user-based access) or Google OAuth2 access tokens (for admin access).
Authenticate with Firebase ID Tokens
See Retrieve ID tokens on the client for an explanation of how to retrieve access tokens in the various Firebase client SDKs. You can also exchange a Firebase custom token for an ID token and refresh token pair via an undocumented REST API:
Endpoint: https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=<API_KEY>
Method: POST
Request Body: { "token": <CUSTOM_TOKEN>, "returnSecureToken": true }
<API_KEY> is the same API key you get from your Firebase Console that you use in the Firebase clients. <CUSTOM_TOKEN> is a Firebase custom token.
Since ID tokens expire after an hour, you will need to use the refresh token to refresh them via this other undocumented REST API:
Endpoint: https://securetoken.googleapis.com/v1/token?key=<API_KEY>
Method: POST
Request Body: { "refresh_token": <REFRESH_TOKEN>, "grant_type": "refresh_token" }
<API_KEY> is the same API key as before. <REFRESH_TOKEN> is the refresh token from the previous API call.
Once you have an ID token, you can pass that to the REST API via the auth query parameter to authenticate a request. The request respects Firebase Security Rules as if the end user logged into the client was making the request.
Authenticate with Google Access Tokens
To authenticate with a Google OAuth2 access token, the first thing you need to do is get one. See Retrieving an access token for an explanation of how to do this. It only currently includes a Java example, but this is possible in many languages, including Node.js. Once you have an ID token, you can pass that to the REST API via the access_token query parameter to authenticate a request. The request will be made with admin access, overriding all Firebase Security Rules and granting full read and write access.

Resources