Azure B2C integration with AWS Cognito Federated Identities - azure

I am the process of integrating Azure B2C with AWS, namely setting up AWS Cognito with Azure B2C as a Federated Identity provider and using it for login purposes for a Mobile App.
For the most part, I believe I have configured everything correctly. This is what I have done so far
I have created a B2C Tenant and set up an "Application" in the tenant as well as a SignUpAndSignInPolicy. The Application has both the native and web clients enabled and also allowed implicit flow.
I have configured my Azure B2C Tenant as an Identity Provider in AWS and have created the necessary Roles for the IdP.
I have created an AWS Cognito Identity Pool and configured it to use the above IdP
I am using the MSAL library to authenticate with Azure B2C, specifically the MSALPublicClientApplication.init(clientId, kAuthority) method followed by acquireToken.
This presents an interactive login in the browser and returns a token to the app via a custom url. The token is valid and I've verified it with the JWT tool.
I then setup an AWSCognitoCredentialsProvider with the Cognito Identity Pool created in step 3 and a custom identityProviderManager which is a class where I have implemented the getToken and logins methods as per AWS documentation .
I then pass the token from step 5 to Cognito via the "return AWSTask(["providerName: "id_token"] statement inside the logins method.
After a ton of going back and forth, I have managed to get through most of the hurdles along the way, however I am now getting a token validation error from AWS, specifically:
error: Error Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=8
"(null)" UserInfo={__type=NotAuthorizedException, message=Invalid
login token. Couldn't verify signed token.}
Googling that error really doesn't produce a ton of results, but from what I can make out, the sequence of events in the app is correct, however AWS is complaining about the validation of the token when it communicates with Azure.
There isn't a lot in AWS that can be configured the Identity Provider, such as secrets, scopes, or any of that, so I'm not really sure where to look.
I am hoping that to a seasoned OpenID pro, this error message means more than it means to me.
Some of the things I'm unsure about that may be relevant.
1. Azure B2C has a concept of "Keys" under an application which I am not currently using, because there is nowhere that I can specify a key of sorts in my implementation.
2. The MSALPublicClientApplication.init method returns an application instance that I then use to call application.acquireToken(forScopes: kScopes). I have no idea what to put for the scopes value because from what I've read, I only need "openid" and "offline_access", but when I try to specify those, I get an error that they're already included by default and that I can specify them in my API call. However, I am not allowed to leave this field blank so at the moment I have the Azure B2C Application ID (in the form of a GUID) which I'm not sure is correct.
Thanks a ton for your help!

Your set up looks correct. Not sure about MSAL library but when testing directly from Azure B2C console, you get different tokens depending on whether you mentioned your signin policy (using 'p' parameter) in the authorize URl. The one without this parameter works but the one with it does not. Something to do with how OIDC Discovery works and how it is configured in AWS IAM console.

Related

Azure Identity SDK (JS) How to Authenticate to User's Azure Account

I am designing my first dev tool with the Azure SDK (JavaScript), and I am having a difficult time understanding how to authenticate users in production so the dev tool can access the user's Azure account. The tool is going to retrieve metrics from all of the user's Azure Functions in their tenant to display React component graphs based on those metrics over time. The app will be run locally with an npm run command.
My entry point for using Azure Identity in my app was this blog post (https://devblogs.microsoft.com/azure-sdk/authentication-and-the-azure-sdk/). I like the way the DefaultAzureCredential is working in development, using the tenant for whichever developer is running it by using the AzureCliCredential. I want a similar functionality for production, but for the browser instead of Azure Cli. In other words, if a user is already logged in to Azure Portal, it will get a credential for their tenant. How do I go about this?
One of the things I tried was opting into the Interactive Browser of the DefaultAzureCredential as described in that blog post. But even though, I could see the browser method in the src (https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/identity/identity/src/credentials/defaultAzureCredential.browser.ts), I couldn't figure how to opt into this when using the actual SDK. I couldn't find that method in the npm package in Azure Identity, and the documentation (https://learn.microsoft.com/en-us/javascript/api/#azure/identity/defaultazurecredentialoptions?view=azure-node-latest) didn't help me either. If this is the correct option for my use case, I would like to understand how to opt into it and use it.
Another thing I tried was implementing the InteractiveBrowserCredential. As long as I pass in a redirectUri with a port not already being used by my app, it did open another tab to tell me to login to the Azure Portal if I am not already logged in. This is exactly the user experience I would want in my app. However, after logging in the credential didn't actually do anything. The credential returned actually has a client Id equal to the application Id (04b07795-8ddb-461a-bbee-02f9e1bf7b46) of Azure CLI (https://learn.microsoft.com/en-us/troubleshoot/azure/active-directory/verify-first-party-apps-sign-in) for some reason. This led me to look into the Interactive Browser Credential and find out that it is using the Authorization Code Flow (https://learn.microsoft.com/en-us/javascript/api/#azure/identity/interactivebrowsercredential?view=azure-node-latest). This flow doesn't seem right for my use case, since I have to register my app. I am not trying to grant users access to my app, but access to their own Azure account. Is InteractiveBrowserCredential what I should be using?
Next, I looked into all of the different authentication flows. None of them seem quite right for my use case though. The closest one I found was the client credentials flow (https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow) since I am authenticating the user to their own Azure account and not my app. However, even this one doesn't seem quite right because when I looked up how to implement that flow with Azure Identity (https://github.com/Azure/azure-sdk-for-js/blob/main/documentation/using-azure-identity.md#clientsecretcredential-and-clientcertificatecredential) I found out that I have to pass in the tenant Id. But the app won't know the user's tenant Id of the user before they log in. Which flow is right for this use case?
It seems like there is a gap in my understanding. How can I use the Azure SDK to implement an authentication flow that authenticates the user to their own Azure tenant (not authenticates them to my app) through the browser?
Thank you ShwetaMathur for answering this question in Q & A. Posting the same here to help Stack Overflow community members.
To access your application by Azure AD users, your application should also need to register in Azure AD.
Once your application is register, you can acquire the access token based on different OAuth flows which is needed to call various resources(Users in your case) or protected API based on your scenario.
Azure Identity TokenCredential provide various flows to obtain an access token based on different scenarios.
InteractiveBrowserCredential is one way to launches the system default browser to interactively authenticate a user and obtain an access token.
Using access token, you can retrieve user’s info or access any other resource in Azure tenant. The InteractiveBrowserCredential uses Authorization Code Flow to authenticate users for browser based applications and to access resources further.
Client credential flow is OAuth flow commonly used for server-to-server interactions that usually run in the background, without immediate interaction with a user and help to acquire the token and call protected web APIs.
Complete reference

Azure Active Directory Oauth 2.0 Client Credentials Flow with API Management Access Token issue

I have had been struggling to make my Azure Active Directory Oauth 2.0 Client Credentials Flow work with API Management. but I get authenticated via postman too. But in return I do not get any access token just a bunch of HTML. How can I fix this? The settings of the applications are exactly as per the documents including the validation of JWT Policy.
Basically I want my client apps to connect with my azure API's using Oauth 2.o without any consent using provided client id/secret. I'm trying to set this up for now with ECHO API provided out of the box with API Management console.
thanks
Postman Access token Error Screen
To use application permissions with your own API (as opposed to Microsoft Graph), you must first expose the API by defining scopes in the API's app registration in the Azure portal. Then, configure access to the API by selecting those permissions in your client application's app registration. If you haven't exposed any scopes in your API's app registration, you won't be able to specify application permissions to that API in your client application's app registration in the Azure portal.
For an example, if I sent scope parameter with custom name like https://testwebapp.in/.default without configuring same as application ID URI in Azure AD then is an expected behavior and you will get error AADSTS500011.
scope parameter in the request should be the resource identifier (application ID URI) of the resource you want, affixed with the .default suffix. For the Microsoft Graph example, the value is https://graph.microsoft.com/.default. This value tells the Microsoft identity platform that of all the direct application permissions you have configured for your app, the endpoint should issue a token for the ones associated with the resource you want to use.
Reference: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#application-permissions

Azure AD, Angular Spa and Spring Microservice Integration

We are using Azure AD for authentication and authorization. Our angular spa has been enabled SSO with Azure AD. We need to secure our backend
service and only allow API which has a valid jwt token.
What we have done so far is:
Registered our angular app in Azure AD.
We have configured spring microservice as a resource server and
application properties contain jwt.issuer-uri
spring.security.oauth2.resourceserver.jwt.issuer-uri=XXXXXXXXXXX-XXXXXXXXX-XXXXXXX-XXXXXXXXXXX
The issue is the token that we get from Azure AD is having an audience as "00000003-0000-0000-c000-000000000000" which means the token is generated for the Microsoft graph. I also tried accessing graph Api with this token and it worked. But what we want is to verify this token in our own spring microservice and grant permission
based on jwt provided.
To solve this issue I had to make some config changes in our Azure registered Angular app. I have added a custom scope api://<>/app and use
this scope while acquiring the token. Now the token is being validated in the backend and API working fine.
This config somehow works but doesn't seem correct to me. I am new to azure so am not sure how all things tie-up.
The new token which is now being generated has an audience as our
angular spa client Id. Is this correct? Shouldn't it be the backend
service? Any why it's getting validated by the backend with the
current configuration?
My understanding is that we don't have to register our spring
microservice with Azure Ad. I will just act as a resource server and
will decode the token provided by the angular app using the
issuer-url.
In case we need to register our backend services with azure AD then
would it be difficult to do the same for all microservices?
I have done all settings by referencing.
https://ordina-jworks.github.io/security/2020/08/18/Securing-Applications-Azure-AD.html
In some other links, I find a completely different config for setting up backend service. I am not sure which one is correct.
https://learn.microsoft.com/en-us/java/api/overview/azure/active-directory-spring-boot-starter-readme?view=azure-java-stable
Azure AD is a little confusing when following a standards based approach. I wrote a blog post on this a couple of years back:
You have already figured out that you need at least one API registration to work, to expose an API scope - so that you get usable access tokens
The generated id from the API entry in Azure then becomes your audience, as in step 9 of the article.
What we'd really like to do is this, so that we can do things like forward the JWT in microservice to microservice calls:
Get Azure AD to issue an audience claim such as api.mycompany.com that is common to all microservices
Issue multiple scopes in the access tokens, based on areas of data in microservices - as in this Curity doc
I would aim for a single entry in Azure AD to represent your platform of APIs. Then each microservice can use the same generated audience value.
Hopefully you can get multiple custom scopes to work also, though there are some annoyances here, especially when you want to use built in OpenID Connect User Info scopes, which Azure AD exposes via the Graph API.

Azure AD authentication fails with error message: "Error validating credentials. AADSTS50012: Authentication failed"

I've been working on a multi-tenant web application that uses Azure AD authentication, and authentication will intermittently fail with the error message: "AADSTS70002: Error validating credentials. AADSTS50012: Authentication failed." To be more clear, the steps I go through are:
Go to my web app, and click on link to go to Azure AD authentication
Enter valid user credentials for Azure
If this is the first time using my web app, Azure asks the user to grant permissions to their Azure AD information
After accepting the permissions, Azure redirects to the reply URL that I've set up in Azure AD for my application, but it replies with the aforementioned error in the URL string
The application itself is a Node.js web app that uses the Passport module for Azure AD authentication, although I don't think Passport is the source of the problem because the error I get is passed by Azure to the web application's reply URL.
I haven't had luck identifying the source, but I have seen posts from people with similar issues. I have a number of AD accounts that I use both personally and for work, and it seems that there is some remnant left in the browser's cache or local storage that causes this issue because I can switch to another browser or into incognito mode and the problem resolves itself.
I'd like to identify if this is a problem with Azure itself, the way my application handles authentication, or with my work/third party applications implement AD authentication.
I am trying to reproduce this issue using the code sample here in Chrome, however failed.
Based on the same issue link you mentioned, I noticed that the endpoint for he/she using was incorrect. To develop the multi-tenant app, we need to change the specific endpoint with common like below:
https://login.microsoftonline.com/common/
Were you using the specific endpoint? If not, would you mind sharing a code sample to help us to reproduce this issue?

WebAPI and Azure AD integration

After a lot of searching, most of the scenarios moves all the authentication to Azure AD and WebAPI just has to know how to read the token. (To achieve this we are using Azure AD middleware in OWIN pipeline). Also, this means that any client that wants resources from the WebAPI has to authenticate to Azure AD on their own (For example: adal.js for JS). Lets say my I want to keep user info within my WebAPI. I suppose I can easily just Create/Read users using some unique field in Azure AD JWT token and I do not need to worry about token validity or any other stuff about security since this middleware does that for me. Simply, I can just use it.
And here comes the mystery that I can not understand.
What if my WebAPI requires specific claims that Azure AD does not provide. For example authorization (permissions and so on) or even organizationId (in multitenant application).
Azure AD works as external identity provider, same as Google, Facebook and so on. But the difference is that most of user authentication logic lives in WebAPI (at least with the examples you can find). Client application receives a list of external providers a WebAPI supports and that is it. This gives an opportunity to introduce LOCAL AUTHORITY tokens with the claims WebAPI would need. But it kind of means that you start creating your own identity service within WebAPI, you also have to manage refresh tokens and so on.
Does it mean that the proper solution would be to start using IdentityServer that integrates variety of external providers and manages token creation with specific claims that my WebAPI would expect?

Resources