Azure AD B2C ROPC - Confidential client flow - azure-ad-b2c

I'm trying to implement a custom ROPC flow in b2c. The idea is that trusted ( internal ) applications can get user tokens without using its primary password ( the user may have several kinds of credentials ), but other credentials.
I'm following the documentation at https://learn.microsoft.com/en-us/azure/active-directory-b2c/ropc-custom?tabs=app-reg-ga , but it clearly states:
Confidential client flow: The application client ID is validated, but the application secret is not validated.
But, from my point of view, these flows should only be used by privileged clients, therefore B2C needs to validate the client_secret, but this is not an option.
Is there a workaround for that, maybe some parameter that I can use in my custom policy definition?
I know that this can be implemented using non ROPC flows, but some applications don't have a way to redirect the user to a web page ( like a TV App ).

Use azure ad client credential flow, it works in B2C tenants too. If it must align to users, have a app reg for each user.
Server side ROPC will get throttled when using AAD B2C endpoint for ROPC policies.
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow

Related

What is the flow of Azure AD based authentication in a project having SPA and web api?

I have a front end SPA (single page application) and back end api.
Each event in the SPA (like button click) invokes the respective api endpoint, and displays the result in the SPA.
I want to implement Azure AD based authentication so that only my Azure Tenant users are able to use the SPA/api.
Is the following flow correct approach to implementing such a feature:
User opens the SPA
User clicks on login button which opens Microsoft login popup
User enters Microsoft credentials in the popup, and if credentials are correct then user gets the JWT token
For every subsequent api request, the JWT token is placed in the bearer header
The endpoint validates the JWT token using Azure public key and rejects the request if token is missing or validation fails.
Is this flow correct and what is such a flow called?
There are several implementation steps that needs to be performed before you will have the flow that you have described:
User flow needs to be configured (Azure AD) - e.g. selfsignup allowed?
Backend and frontend applications needs to be registered (Azure AD)
Permissions and scopes needs to be added (Azure AD)
Backend API needs to be configured (e.g. API management) in order to validate the JWT token
I highly recommend to configure one of the Azure sample implementations end2end to get and idea of all the needed tasks: https://learn.microsoft.com/en-us/azure/active-directory-b2c/configure-authentication-sample-spa-app
The steps you outlined are correct.
An OAuth 2.0 "flow" outlines the steps to acquire a token from an Identity Provider (IdP). Since you are using a SPA, there are some restrictions on which flows you can use. A SPA can't act as a "Confidential Client" which is required for some flows. (Basically - the Client Secret required for the other flows would be visible in the browser network trace, so it's not "confidential".) The "Implicit Flow" used to be recommended for SPAs but it's less secure, so now the "Authorization code flow (with PKCE)" is recommended. Steps 2 & 3 in the question above are when you are executing the flow to acquire a token.
The authentication flow doesn't really address how you save and send the token to the API (#4 in the question), but the Microsoft Authentication Library (MSAL) helps with that - More information here - https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-spa-overview
In Azure AD, you'll want 2 App Registrations - one for your SPA and one for your API. The API App Registration will need to "Expose an API" which really means to define a scope. Your SPA App Registration will need to Add an "API Permission" to the scope you defined from your API App Registration. (It will show up in My APIs.) This relationship is how #5 in the question is enforced.
Many of the steps for setting up authentication in Azure AD and Azure B2C are similar but Azure AD is designed for authenticating users that are part of your organization. Azure B2C allows you to build a set of users that aren't members of a particular Azure AD organization.

Can we use client credentials flow on regular Azure users?

We would like to use Azure client credentials flow to do authentication for our service accounts. The thing is our service accounts are just regular users in Azure AD. They are not registered apps. The way our company sets up Azure makes it very heavy to register apps, so we would like to avoid it. So the question is, can we use client credentials flow for regular users in Azure? We need this as in our CI/CD we cannot popup a browser and let users do device-based authentication. We need the user to be able to authenticate in an automated way.
You can't use client credentials flow where an Azure AD user is involved in the authentication flow.
Micrsofot Documentation - client credentials flow
This type of grant is commonly used for server-to-server interactions that must run in the background, without immediate interaction with a user.
But you can use one of the following supported authentication flow where a user is involved;
Micrsofot Documentation - authorization code flow
Micrsofot Documentation - implicit grant flow
Micrsofot Documentation - device authorization grant flow
Device authorization grant flow might work in your case?

Azure AD B2C: mixing built-in flows with custom policies and sharing encryption keys for JWTs

I’m working on an app that uses Azure AD B2C and .NET Core APIs. We are trying to use a mixture of built in user flows and one custom policy. Built in user flows for sign-in and reset password, and a custom policy for sign-up because we want to follow the invitation sign-up flow demonstrated by this sample app.
https://github.com/azure-ad-b2c/samples/blob/master/policies/invite/README.md
An issue I’m having is on the API authorization side. The JWTs issued from the built-in user flows are encrypted and signed with a different set of keys than the JWTs issued from the custom invitation policy. If I setup the B2C authority for my API project to reference my sign-in flow https://{mytenant}.b2clogin.com/investgradedev.onmicrosoft.com/B2C_1_SI/v2.0 then tokens issued from sign-in are authorized fine but tokens issued from sign-up fail authorization. If I set the B2C authority to reference the custom sign-up policy https://{mytenant}.b2clogin.com/investgradedev.onmicrosoft.com/B2C_1A_signup_invitation
/v2.0, then I have the reverse problem.
Is there a way to have the tokens from both flows encrypted and signed using the same keys? If so, how to I set this up?
Should I force new users back through the sign-in flow to get a token that works?
I’m new to B2C and have been on a steep learning curve so any help provided is greatly appreciated.
No you cannot.
This is possible workaround.
Other option, add multiple Authorities into the API. I did this with AAD and AAD B2C as an example:
https://github.com/azure-ad-b2c/apps/tree/master/apps/spa-hellojs-popup/source-code/.Net-Core-API-RBAC
https://github.com/azure-ad-b2c/apps/blob/master/apps/spa-hellojs-popup/source-code/.Net-Core-API-RBAC/MultiBearerAPI/Startup.cs#L30

How to authenticate and store tokens in a multitenant web client (multiple B2C identities in the same browser)

I'm designing a single-page app (SPA) and API that will support multiple tenants, including in the same client browser. Imagine an experience similar to the Azure Portal, where users can switch between identities that they have signed into Azure AD with, except that in this case I'm using Azure AD B2C. All sign-ins happen via a single Azure AD B2C instance. Importantly, the tenants do not necessarily have to be aware of each other since they are white-labeled -- the user might be redirected to https://multitenant.app/tenantA and sign in via B2C, and have a totally different experience when directed to https://multitenant.app/tenantB and signing in via B2C there. The two tenants do not need to share data between themselves on the client.
How might I go about:
1) designing the client so that requests to https://multitenant.app/tenantX are directed to Azure AD B2C in a way that enables sign-in using the rules for tenantX, and
2) designing the client so that the MSAL.js library correctly provides a token store containing tokens specific to tenantX when the user has navigated to https://multitenant.app/tenantX in the browser?
Currently I'm expecting to need to intercept requests to the backend API on the client, determine if a redirect to B2C is necessary first in order to sign in to the tenant that the request is for, and attach the appropriate access token for that tenant to the API request. (All this is assuming that I use the Implicit Flow so that I have the access & refresh tokens available on the client.)
Does this make sense? Is there a better way? I've debated using session cookies issued by the server so that the browser handles the "intercept-requests-and-attach-credentials" aspect of this, so maybe that's an option that would avoid the need to maintain all these tokens on the client?
And how does this work when the client signs into B2C? Can I tweak/disable the B2C SSO capabilities sufficiently so that a single user agent (browser) can still obtain multiple different tokens (for different identities)?
The approach needs to be a bit different. This is how Microsoft do it with their "tenant picker" in the Azure Portal.
We hold a mapping of in which tenants your account lives in
We then list the tenants in a tenant picker UI in the app
When you switch tenants, we do an SSO authentication to the new resource (ie the selected tenant) to get a token to it
We use the new token to evaluate your rights in this tenants subscription
To translate this in AAD B2C you can:
Hold a mapping of identifier to 'tenant'
On authentication, call your API to get a list of tenants. Use this sample to list the tenants in the authentication flow
The user selects the tenant, or maybe you do it like Microsoft and have a default preference, in which case the step above is skipped using a B2C precondition. This way the user only goes through selecting a tenant in the auth flow once. Afterwards they use an in-app tenant picker (read on...)
The token issued to the user has the tenant inside it as a claim, this will then be used to do authorization when this token arrives are your API.
In the SPA, now render a tenant picker, use the same API as used in step 2 essentially
The user can select a new tenant in the SPA, use id_token_hint (example) to seed a new B2C user journey with the selected tenant. The user will get SSO through this journey and get a new token with the new tenant inside it as a claim.

Why signing in Apps via OAuth ROPC flow is not recorded in AAD sign-in logs?

When I use ROPC (Resource Owner Password Credential) flow in my App to let users to sign in my App, why I cannot see any sign-in logs in AAD with it?
ROPC is defined in OAuth2 protocol: https://www.rfc-editor.org/rfc/rfc6749#section-1.3.3 and it’s not included in OpenID Connect.
It just likes other flows in OAuth2, they’re designed for protecting API resources, not authenticating users.
The behavior of ROPC in AAD:
For the ROPC flow, user inputs his/her AAD username and password in the client app side. Then the client sends the user’s credential to AAD. It shows as this below picture:
This behavior may cause a main risk: The client may store and upload the user’s AAD credential and used it for other things. It can play as a phishing app to obtain user’s AAD credential.
Generally, in claims-based authentication, clients should just obtain a user’s attributes(E.g. claims in OIDC id_token, SAML token) issued by a trusted IDP to identify the user. Client shouldn’t obtain the user’s credential for other Identity providers.
Why it’s still supported in AAD?
We can see lots of our customers want to use ROPC flow to delegate user permissions to run a job automatically. Some of our customers use ROPC for their own customized login experience.
From Microsoft side, AAD supports ROPC flow as we can really understand it’s necessary in some special scenarios.
So, what kind of app we can use ROPC in it?
All client apps should be public client(Native App) first.
In Microsoft 1 party Apps, like Powershell.
In User’s owned/trusted Apps.
How can we avoid being phished by a 3rd party app which prompts AAD login?
Make sure the page prompts you to input your AAD user credential is AAD login page. You can also check the domain in the URL. It should be start with “https://login.microsoftonline.com/”.
Generally, we shouldn’t input the username and password together in one form. If a 3rd party app asks you to input your AAD username and password in one form, you need to be careful and don’t try to login it via your AAD credential here. Because AAD doesn’t provide any login page to let you enter your user credential in one form currently.
Overall, user login via ROPC flow may be a sign-in event for the client but it’s not a sign-in event for AAD as the user is not signed in AAD.

Resources