I'm using Azure Functions to be the middleman between my Xamarin Forms app and my ComosDB Table. I think I understand how authentication works using Active Directory B2C, but I'm unclear about how authorization checks take place.
My understanding is that I can enable Active Directory B2C to authenticate the user and give them an access token. I can then make an http call to an Azure Function with the token as a parameter. How do I check that the token is correct for that user. Ultimately, I want to protect the data in the Table and only give data relevant to that specific user.
There are at least 2 approaches to validate tokens in Azure Functions:
The first is that you could do it manually: https://github.com/Azure-Samples/ms-identity-dotnet-webapi-azurefunctions/blob/12640a348852696ac0d01e7adfd937900ef8ea40/Function/BootLoader.cs#L73.
This uses Microsoft.IdentityModel.Protocols.OpenIdConnect and System.IdentityModel.Tokens.Jwt to get the configuration from the metadata endpoint and validate the token.
The main difference for you would be the openid-configuration URL, which you can get from the view that allows you to run a B2C user flow for testing in Azure portal.
Another approach is to use App Service Authentication: https://cgillum.tech/2016/05/27/app-service-auth-and-azure-ad-b2c/.
Related
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.
I have Azure Functions which i want to authenticate using access token.
I have following things set up
Azure App which is being used by Angular SPA to authenticate user
Access token which is used to invoke graph APIs, Permissions are set in Azure app (point 1)
Azure Function which is having http triggers (APIs) which are being used by SPA
Currently, APIs are anonymous and can be invoked from anywhere. i want to secure these apis using access token which is being used by graph api (point 2)
I think the best approach for me is AAD multi tenant authentication. However, When i click on "Authentication (classic)" it gives me This app is configured using the new authentication experience. Click here to access Authentication (preview).
Also, if i keep authenticated with following options, i get "You do not have permission to view this directory or page." error
Most of the articles which i find online are talking about AAD. for me that option is not enabled.
I have tried following articles to make it work but somehow its not happening. can anyone suggest. how can i achieve this.
https://medium.com/medialesson/protecting-azure-function-apps-with-azure-ad-authentication-authorization-fd167ce4fe33
https://medium.com/geekculture/easyauth-in-functions-app-with-azure-active-directory-29c01cad8477
is there something i need to do in my existing Azure app to make it work ?
Per my understanding, your Azure function is protected by AAD using Authentication(Easy auth). And now, your angular SPA would like to access this function. Pls follow the steps below:
Go to Azure AD => App registrations => The App you created to protect your Azure function=> Expose an API to add a scope, for instance, access_as_user so that your SPA could require an access token for this scope:
Got to Azure AD => App registrations => The App you created for your SPA app=> API permissions => Add a permission => My APIs to grant the scope we just created:
Click the grant admin consent button to finish the process.
In your SPA app, use MsalService to acquire an access token with scope: api://<your azure function app id>/access_as_user, by this token, you can access your Azure function. For a quick test, I just test it in post man and it works perfectly:
Not use this access token
Bring this access token
UPDATE
Basically, your app request diagram as below:
SPA (request with access token)==> Easy Auth of Azure function (valideate token,if pass,goes into Azure function code logic,if not, return 401)==> code logic of Azure function (obo flow to get access token for Graph API) ==> call Microsoft Graph API
By now, we have finished steps 1 and 2: get access token for easy auth and pass easy auth goes into Azure function code logic.
So in the Azure function code logic, we need to do 2 things:
Get the access token in the request header
Use the access token and OBO flow to exchange a new access token for Microsoft Graph API. Just refer to request below to use OBO flow to exchange an access token for Microsoft Graph API:
BTW, pls make sure that your Azure function app has been granted with permission user.read and Calendars.Read:
So that you can get a new access token to call Microsoft Graph API:
May be this will help someone, I have tried using above suggestions but could not achieve 😠instead i am using Key for each Azure function. and storing those keys in azure Key/Vault and retrieving those keys within App settings of the application using managed identity. This may be not be the ideal situation but i think it will do for me at the moment. I really hope MS will improve their documentation some day along with sample code/steps
I am using an Azure ADB2C tenant to sign-up/in users with custom policies and rest api claims exchanges. This works fine.
Now I would like to start a service (daemon) that runs in a cloud environment for each user that signs-up with my service. This background service will access resources on other servers. Accessing these resources require a token and the service should only have access to the resources that the user has (i.e.: the access token used by the background service should also include the custom REST API claims). For the common users, this is taken care of by my REST API claims server, which enriches the token in such a way that it gives users' access only to the allowed resources.
I have found this page describing how to get access without a user. But this page assumes that the background service is a single instance that has access to all users' data that it needs. My background service is a 1-to-1 mapping to the signed up user.
Ideally this is how I see it working:
A new user signs up.
My REST API claims exchange gets called for this user.
Call Azure ADB2C to create a token for the background service. (Token should also contain my custom claims)
Start a new instance of the background service using the token created at step 3.
Return the custom claims for the new user.
This will happen for every new user, so every user in my system will have a corresponding background service running in the cloud.
Is this possible with Azure ADB2C? If yes, how?
The link you provide to get access without a user is only suitable for calling ms graph api and not for calling custom api.
If you are calling ms graph api, then you can indeed use the daemon-based client credential flow to obtain an access token (that is, without user involvement). This flow is usually used in Azure AD, but if it is used to call ms graph api, then it is also applicable to Azure AD B2C.
But if you are calling a custom api, then you must use a user login flow. Azure AD B2C obtains tokens in a different way from Azure AD. To use Azure AD B2C, you must first create a policy to enable users to sign up and sign in to your application.
I have a Web App (VueJS + ASP .NET Core backend) hosted on Azure App Service and I use Azure AD B2C for authentication. I also have a Functions App that I want to call from the client code but I’m not sure what’s the best way to flow the auth to the Functions.
I can register the Functions App in B2C and set Easy Auth but how do I flow the already authenticated user from the client to the Function?
I can create a custom JWT token and be done with it but is it possible to flow a B2C token to the Function? If so, how do I validate the token?
If Easy Auth didn't work for you, there is a workaround and yes it is a manual task.
Send B2C token in header while calling Azure Function
Read the token at the function level and validate the JWT token.
You can easily validate JWT token by decoding/ writing simple code
Check Validate JWT SO post
This manual validation also secure and safe to use.
You can handle Azure B2C validation the same way I did here Github
There are several problems to handle:
1. Load token from valid b2c policy
2. Validate it depending on rules set.
3. Setup Validation on Startup/Attribute in order not to create boilerplate code.
4. Currently AF 2.0 does not support invocation short circuits, so you need to properly handle your 401 codes.
I create an Azure APIM instance, register it as an app in AD and then create a OAUTH2.0 server under APIM which is setup using the clientid/secret key of above registered app. I make a dummy API under this APIM and then protect it with this OAUTH2.0 server. I also add a JWT policy on my api to look for a token and authenticate against the tenant-id.(No claims mentioned).
Now lets say, i have a Customer (ABC) and for that i register another app in AD and create its Clientid/secret. Customer generates its token with the help of token endpoint (this endpoint is given under Endpoints tab of AD app registration option). Customer calls the API with this token and it works.
Issue: I didn't give any permission for my APIM App in AD to the Client App in AD but it still works, which essentially means that any Clientid/secret from any app registered in AD will go through my JWT policy of the API. Because it is just validating against the tenantid. How can we stop this and make sure that it works only for a customer to which permissions is given.
This is one of the major things I mentioned in my recent article: https://joonasw.net/view/azure-ad-authentication-aspnet-core-api-part-1.
Any app of type Web App/API in Azure AD can get a valid access token for any API in that Azure AD tenant.
Even before any permissions are given to it.
This is kind of a "feature" I guess.
Quote from the article:
If you only require an authenticated user, any confidential client in your Azure AD can acquire an access token for your API and call it. So it is important that you implement the user_impersonation scope check at minimum.
Now since your caller will call your API as itself, you need to implement an App Permission.
You can see how those are defined here: https://joonasw.net/view/defining-permissions-and-roles-in-aad.
Then implement a check that ensures the roles claim contains the value of the app permission you defined.
The claim will be a string array, so some kind of contains check needs to be made.
This will then require that this app permission is granted the caller before they can make the call successfully.
If you also want to allow delegated calls (i.e. calls on behalf of a user),
then add an optional requirement for the user_impersonation scope.
Those are stored in a single string claim (scp), space-separated.
So for that one you'll need a contains check on the string.