Calling web api from SPA giving error: Azure AD b2c - oauth-2.0

Here is my aim: I would like to get an access token to call web api from my Spa application.
I created 2 azure b2c applications; one for web api and other for spa application(client).
I added scopes(api.read) by exposing api in web api application. I granted permission to these scopes from spa application.
I created one userflow with Sign up and sign in policy.
To generate the token, I used PKCE flow by getting auth code.
POST
https://tenant.b2clogin.com/tenant.onmicrosoft.com/policy/oauth2/v2.0/token
grant_type: authorization_code
client_id: api_appid
scope: https://tenant.onmicrosoft.com/web_api/api.read
redirect_uri: https://localhost:435
code:
code_verifier:
The thing is I get the token but while calling the web api, it's giving error like:
Either scp or roles claim need to be present in the token
What could be the problem?

I tried to reproduce the same in my environment and got below results:  
I registered one Azure AD B2C application for Web API and added scopes 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:
When I signed-in as a user it gave me auth-code in address bar like below:
I generated the access token via Postman with parameters 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/web_api/api.read
redirect_uri: redirect_uri
code: code
code_verifier: code_verifier
When I decoded the token, I got the scp claim successfully like below:
Make sure to select Application as SPA App and resource as Web_api while running the user flow to get auth code.
While generating access token, you should give SPA_AppId in client_id parameter.

Related

OAuth2 flow for securing a REST API

I have Keycloak for authentication and authorization of multiple applications (a web page and a REST API). From my understanding the flow for the web page when using OAuth2 authentication_code grant type is as follows:
In this flow, in the second step (the one in red) the resource owner logs in because she/he were redirected to the login page of Keycloak. This flow is clear to me and is working well.
But, with the REST API I don't know what is the process to authenticate and authorize the user (resource owner), because there isn't a browser to redirect him to the login page of Keycloak. So, I tried with the password grant type and it worked, but then I realized that this grant type is deprecated. So I tried again with the authorization_code grant type but can't make it work. I am trying to get the token using the following request:
URL: http://localhost:8080/auth/realms/somerealm/protocol/openid-connect/token
Body:
username: someuser
passwoord: somepassword
grant_type: authorization_code
client_id: someclient
secret: somesecret
The problem is that I am receving the following response:
{
"error": "invalid_request",
"error_description": "Missing parameter: code"
}
I know I have something wrong in the request (and in my understanding of OAuth2), but I have read a lot and can't discover what it is.
API (backend) doesn't need any login flow usually. It just needs to verify token and then it executes requested operation or it denies it (response code 401 - problem with authentication / 403 - problem with authorization). It doesn't redirect to auth server.
Client, which is using API must obtain token before API request. It can be done by the frontend (e.g. SPA with The Authorization Code Flow + PKCE) and then frontend maintains state (token refresh, error codes from the API, ...).
If you don't have any frontend, then procedure how to get token must be part of API specification. For example see swagger doc: https://swagger.io/docs/specification/authentication/oauth2/
The Client credentials flow should be used machine to machine authentication, so it's not a solution if you need to know user identity.
With the authorization_code grant type you have to spawn a browser in some way.
password is unfortunately deprecated, but the recommendation is to use client_credentials for these cases now. I hope this decision get reversed before OAuth 2.1 is released.

Does Oauth Authorization Code flow generates a service principal sign in event?

in Oauth Client credentials flow, when application gets an access token after authenticating using the credentials There will be a Service Principal SignIn event.
I wanted to know whether there will be a SPN SignIn event for Oauth authorization code flow as well. Here the client id, auth code and client secret (incase of web app) is sent to Oauth token endpoint to get a access token. But I'm not sure if it will generate a SPN Sign In event.
No, when you use authorization code flow, it will not generate a SPN Sign In event.
It will generate a new record(under "Service Principal sign-ins" tab) when you use client credentials flow, because client credential uses a service principal to do authentication (shown as below screenshot).
But when you use authorization code flow, it will generate a record under "User sign-ins (interactive)" tab like below screenshot. Because authorization code flow uses user account to do authentication but not service principal.

No access token returned for AD B2C user when requesting Microsoft Graph delegated permissions

User Story: Given an ADB2C User, with Global Administrator role and an oid of 01234567-901a-bcde-f012-3456789abcde (not a real oid), I want to be able to log in as that user and retrieve the user profile from "https://graph.microsoft.com/beta/me" or "https://graph.microsoft.com/beta/users/01234567-901a-bcde-f012-3456789abcde". Both are listed in the documentation as valid endpoints for B2C.
It's not working:
In an app registration with only Microsoft Graph permission scopes assigned, I used postman to request a bearer token for access to MS Graph. There is one Web redirect URI (https://oauth.pstmn.io/v1/callback), one client secret, and implicit grant is on for both access and id tokens.
The scopes requested are: openid offline_access https://graph.microsoft.com/Directory.AccessAsUser.All
Again, the B2C user account has the Global Administrator role.
The Implicit flow returns the error message
AADB2C90205: This application does not have sufficient permissions against this web resource to perform the operation.
The Authorization Code flow, when the app secret is included, lacks an access bearer token. There is an ID token and a refresh token, but no access token. That's with and without PKCE, whether or not I send the authorization to an external browser.
The app in my tenant has a user flow, B2C_1_postman, which is basically default. It works just fine with postman, other test apps, and the "Run User Flow" function in the B2C management blade.
The auth endpoint is:
https://{Tenant}.b2clogin.com/{Tenant}.onmicrosoft.com/B2C_1_postman/oauth2/v2.0/authorize
The token endpoint is:
https://{Tenant}.b2clogin.com/{Tenant}onmicrosoft.com/B2C_1_postman/oauth2/v2.0/token
I've duplicated this behavior with a couple of desktop demos from Microsoft's github repository, and now with Postman. The app, called "postman", is in the ADB2C tenant. I granted it the app API scopes of:
Directory.AccessAsUser.All
Directory.Read.All
Directory.ReadWrite.All
Directory.email
Directory.offline_access
Directory.profile
This procedure mirrors what the desktop demo at https://github.com/Azure-Samples/active-directory-b2c-dotnet-desktop sets up, with the single exception being that instead of a NodeJS sample app, I want my desktop app to use MS Graph. (This app registration works just fine if I add the endpoints for the sample app. But specifying the MS Graph scopes always returns an empty access ID.)
How can I get this to work?
Managing users through Graph API still seems to require usage of application permissions.
So instead of adding delegated permissions to the app in B2C, you need to add application permissions, where you call the Graph API as the app, not on behalf of the user.
The instructions in the docs explain the app registration in detail: https://learn.microsoft.com/en-us/azure/active-directory-b2c/microsoft-graph-get-started
You need to give this app application permissions to Graph API, not delegated permissions.
Then use those app credentials purely to call Graph API.
And you need to use the underlying Azure AD's token endpoint instead of your B2C policy token endpoint.
Since your app is a desktop app (a public client app), you'll need to do the Graph API interactions in a back-end service to which you can authenticate with a B2C token acquired on behalf of the user.
Mass confusion here.
You can definitely do what you are looking to do, except that this is all Azure AD functionality, not Azure AD B2C. So you are not looking to invoke any B2C user flow etc. B2C auths cannot get access to Microsoft APIs, only your own APIs.
AAD tenant - contains only AAD endpoints. It is a single token issuer
B2C tenant - contains both AAD and B2C token endpoints. There are two token issuers respectively
A B2C tenant contains:
AAD endpoint: login.microsoftonline.com THIS IS NOT BEING DEPRECATED
AAD B2C endpoint: tenantName.b2clogin.com+ B2C policyId parameter
Based on the authentication request, the request is routed to the two different token issuers.
The next key point:
AAD endpoints allow you to obtain tokens to your applications protected by an AAD Application Registration.
AAD endpoints allow you to obtain tokens to Microsoft APIs, since they are also protected by AAD on our side. Such as MS Graph API.
AAD endpoints allow client_credentials
B2C endpoints allow you to obtain tokens to your applications only protected by an AAD B2C Application Registration.
B2C endpoints do not allow client_credentials
You cannot use tenantName.b2clogin.com to obtain a token for MS Graph API, based on the above rule set.
This means a users B2C authentication cannot be used to authorize to AAD protected apps, or Microsoft APIs. (Eventhough the new App Reg experience allows assigning the permissions to MS Graph for B2C Application Registrations- we are looking to fix that).
When you use login.microsoftonline.com and don't provide any policy id parameters against a B2C tenant, you hit the AAD endpoints of the B2C tenant, again it works. You can get tokens to Microsoft Graph API for example, using the users context.
When you use tenantName.b2clogin.com and provide any policy id parameters against a B2C tenant, you hit the AAD B2C endpoints of the B2C tenant, now it will not work as you expected it to. Hopefully the above clarifies why. And since there is no deprecation of the AAD endpoint, you don't need to be using this domain name for this type of call.
The summary is, treat your scenario as a pure Azure AD scenario, as per this sample. You create an Application Registration for Accounts in this organizational directory only. when prompted for the type.

OAuth2 authentication code for already logged in user

With an OAuth2 implementation (either developed in-house, or a 3rd party like Google, Facebook, Login With Amazon, etc.), is it possible to generate an authentication code on behalf of a user logged into a mobile app or web app without requiring any action from the user?
The typical flow to obtain the authentication code requires the user to authenticate and authorize the requested scope. But in this case, the user is already authenticated into the app, so I want to avoid requiring the user to log in again.
The authentication code is required for invoking an external third-party API that will eventually exchange the authentication code for refresh/access tokens. The backend system (associated with the API) needs to get its own refresh/access token based on the authentication code shared with it. This is not for a one-time use of the token; the system needs to have its own tokens for that logged in user, independent of the mobile client.
It is possible to get user token for another client. You do not need new authentication code, you just call token endpoind with some params. For example, in Keycloak this flow is called Token Exchange. You need to configure clients in the Keycloak and then you can call token endpoint with access token you have.
{
client_id: your client id,
client_secret: your client secret,
subject_token: token you have
audience: target client id,
grant_type: urn:ietf:params:oauth:grant-type:token-exchange,
requested token type: urn:ietf:params:oauth:token-type:refresh_token
}
You can read about this flow here:
https://tools.ietf.org/id/draft-ietf-oauth-token-exchange-12.html
It is also called On-Behalf-Of flow like in Azure:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow

AWS Cognito - using scopes in authorizing access to api gateway

I have setup a Cognito user pool so that I can use it to authorize access the an api gateway. It uses OAUTH2 and the flow im using is : Authorization Code Grant,
Scopes : email, openid and profile,
Allowed Custom Scope : product-api/read_product, product-api/create_product, product-api/delete_product
I use boto3 admin_initiate_auth command to connect to the user pool:-
response = idpclient.admin_initiate_auth(
UserPoolId=USERPOOLID,
AuthFlow='ADMIN_NO_SRP_AUTH',
AuthParameters={
'USERNAME':USERNAME,
'PASSWORD':PASSWORD,
'SECRET_HASH':SECRET_HASH
},
ClientId=APPCLIENTID
)
and the response I receive is a json object with several fields, which include access_token, refresh_token etc...
but when I use the access_token to access the api gateway, i get a 401 error. Unauthorised. Looking into the access_token it looks like the custom scopes have not been added.
Could you advise why the custom scope has not been added to the access_token and how do i get the custom scopes added ?
the api gateway has a lambda authorizer added.
Usually you have to specify the Scopes in 2 places:
The OAuth client entry for the client application in the Cognito section of the AWS console
The code requesting a token - I have always implemented this in a standards based manner whereas you are using an AWS specific solution
Looks like what you want may not be supported via admin_initiate_oauth:
Include user details in AWS Cognito Oauth2 token
If your client application is a web UI then the standards based solution will do what you want.
I've tested my Cognito single page app sample with custom scopes - you can run it here:
https://authguidance.com/home/code-samples-quickstart
Not sure if this type of solution will work for you though ..

Resources