Why is SignUpSignInPolicyId required for an API? - azure-active-directory

This sample here shows providing a SignUpSignInPolicyId https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/4-WebApp-your-API/4-2-B2C
See the appsettings.json for the service (Web API):
"AzureAdB2C": {
"Instance": "https://fabrikamb2c.b2clogin.com",
"ClientId": "90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6",
"Domain": "fabrikamb2c.onmicrosoft.com",
"SignedOutCallbackPath": "/signout/B2C_1_susi_reset_v2",
"SignUpSignInPolicyId": "B2C_1_susi_reset_v2"
//"CallbackPath": "/signin/B2C_1_sign_up_in" // defaults to /signin-oidc
},
I am confused what this does with an API, the API is protected by OAuth2 JWT it cannot control sign up or sign in at all. It just takes a token and validates it.
Why does it need to know anything at all about a sign up or sign in policy?

When I tried to run the application which calls api with policy ,I can login and open the redirect to app.
Appsettings.json
{
"AzureAdB2C": {
"Instance": "https://kavyab2c.b2clogin.com",
"ClientId": "xxxxxxx",
"Domain": "kavyab2c.onmicrosoft.com",
"SignedOutCallbackPath": "/signout/B2C_1_susi",
"SignUpSignInPolicyId": "b2c_1_susi",
"ResetPasswordPolicyId": "b2c_1_reset",
"EditProfilePolicyId": "b2c_1_edit_profile" // Optional profile editing policy
//"CallbackPath": "/signin/B2C_1_sign_up_in" // defaults to /signin-oidc
},
Even without policy it redirected to page.
But to obtain claims or reach the particular controller action or access an api, it requires user authentication if one needs to protect API.
Note:
SignUpSignInPolicyId should not be omitted when calling an Azure AD B2C protected API. If it is not specidfied, the API will not know which user flow to use and cant authenticate the user and gives error.
If custompolicy is used instead of userflow, the SignUpSignInPolicyId
parameter can be omitted, and the created custom policy can be used
to authenticate and authorize users directly by making use of their
username and password credentials.
Reference: Cloud authentication with Azure Active Directory B2C in ASP.NET Core | Microsoft Learn

Related

ASP Net Core API downstream call to Graph API W/ AADB2C

I have an ASP Net Core API where I want to call Graph API. I configure the Authentication as such:
services.AddMicrosoftIdentityWebApiAuthentication(Configuration, configSectionName: Constants.AzureAdB2C)
.EnableTokenAcquisitionToCallDownstreamApi(options => Configuration.Bind(Constants.AzureAdB2C, options))
.AddMicrosoftGraph(Configuration.GetSection("GraphAPI"))
.AddInMemoryTokenCaches();
My appsettings.json file has the following properties:
{
"AzureAdB2C": {
"Instance": "https://tenantName.b2clogin.com/",
"Domain": "tenantName.onmicrosoft.com",
"TenantId": "tenantId",
"ClientId": "appId",
"ClientSecret": "appSecret",
"SignUpSignInPolicyId": "B2C_1_SignUpSignIn",
"ResetPasswordPolicyId": "B2C_1_PasswordReset"
},
"GraphAPI": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": "User.Read Directory.ReadWrite.All"
}
}
My b2c app is granted permission to these Graph scopes.
I created an endpoint:
[HttpGet]
[Route("me")]
public Task<User> Me()
{
return this.graphServiceClient.Me.Request().GetAsync();
}
This is where I get this error:
ErrorCode: unsupported_grant_type
Microsoft.Identity.Client.MsalServiceException: AADB2C90086: The supplied grant_type [urn:ietf:params:oauth:grant-type:jwt-bearer] is not supported.
Why can't my API call GraphAPI? All samples that I saw used services.AddMicrosoftIdentityWebAppAuthentication.... Could that be the reason?
On-behalf-of flow in B2C is not supported: https://learn.microsoft.com/en-us/azure/active-directory-b2c/access-tokens.
Web API chains (On-Behalf-Of) is not supported by Azure AD B2C.
You need to acquire the token using application permissions as your application with client credentials flow.
There is some documentation on that: https://learn.microsoft.com/en-us/azure/active-directory-b2c/microsoft-graph-get-started?tabs=app-reg-ga#register-management-application.
The documentation creates a separate app registration for doing that though I think you can just add the app permissions to your existing registration.

Call Microsoft Graph API to get user in Azure AD B2C

I have an android application that uses Azure AD B2C. Users can sign up using local account/email. Once the user logs into the android application, I'm trying to call the Microsoft Graph API to get the signed-in users details (specifically the Graph API UPN of the user, which is different than the UPN in Azure ad B2C).
The API call I'm trying to make is: https://graph.microsoft.com/v1.0/me
I added the bearer auth token I receive when the user logs in.
However, I receive the following error:
"error": {
"code": "InvalidAuthenticationToken",
"message": "CompactToken parsing failed with error code: 80049217",
"innerError": {
"date": "2020-06-17T06:11:32",
"request-id": "b4e9757e-60d9-453f-820d-9f817831aa0c"
}
}
}
Any idea what I can do to get the user's Graph API UPN? Appreciate the help!
This error occurs when the token used is invalid. If you want to get the logged-in user information, you can request the API at here.
Don't forget to grant administrator consent for this permission,please checkhere.
Update
For Azure b2c users, it is currently not possible to call the Graph API.https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/526

Secure .Net Core 3 Web API with AAD Token

Due to some technical constraints, we are doing Username/Password AAD authentication when user login.
Users will input their username and password into our custom login page and our application calls IPublicClientApplication.AcquireTokenByUsernamePassword.
I'm planning to use the returned token to call another Web API application(also connecting to the same AAD). In the Web API application, I did the following:
Added the following code in startup services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme).AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
include the following settings in my appsettings.json file
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "<Application ID>",
"TenantId": "<Tenant ID>"
}
Secure my web api using [Authorize]
I then use Postman to construct a call to the Web API based on the returned token. I included Authorization: Bearer <JWT Token>. The Web API returns
Bearer error="invalid_token", error_description="The signature is invalid"
My questions are
Can Web API application validate the username/password acquired token?
If the token can be validated in Web API application, how can I do it since I'm getting the above error?
I test in my site and it work well, you could refer to the following steps:
1.Register Webapi app in azure ad.
2.Click Expose an API and Add a scope e.g. webread.
3.Click Manifest, change accessTokenAcceptedVersion to 2.0.
4.In visual studio webapi ConfigureServices:
services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme).AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme,
options =>
{
options.Authority += "/v2.0";
options.TokenValidationParameters.ValidAudiences = new[]
{
options.Audience,
$"api://{options.Audience}"
};
});
5.Register client app in azure ad.
6.Click Authentication, set Default client type as Yes.
7.Click Api Permission>Add a permission, select My APIs and choose the webapi your registered before.
8.In visual studio client app, set scope with webread:
string[] scopes = new string[] { "api://1890e822-xxxxxxxxxxxxxxxx/webread" };
Hope it helps you.
From the document you provided you are using MSAL to get access token using Resource Owner Flow in Azure AD V2.0 endpoint .
From document , when validating access token which issued from Azure AD V2.0 , you should add /v2.0 to Authority :
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
{
// This is a Microsoft identity platform web API.
options.Authority += "/v2.0";
// The web API accepts as audiences both the Client ID (options.Audience) and api://{ClientID}.
options.TokenValidationParameters.ValidAudiences = new []
{
options.Audience,
$"api://{options.Audience}"
};
});

Why can't I access my Azure Function when it requires authentication?

(I apologize for the length of this question; I wanted to be thorough.)
I'm new to Azure and am trying to set up a "serverless" API which requires authentication. I have a Function which behaves correctly when authentication is not enabled (basically just "Hello, world" in Node.js). However, when I enable authentication, the only response I get is:
You do not have permission to view this directory or page.
To enable authentication, I:
Went to Azure Active Directory in the Azure portal.
Went to App Registrations.
Created a new registration for my Functions app.
Added a Web redirect URI of https://<myapp>.azurewebsites.net/.auth/login/microsoftaccount/callback.
Created a new client secret for my app.
Went to my app from the Dashboard, selected the "Platform features" tab, and clicked on "Authentication / Authorization".
Enabled "App Service Authentication".
Configured the Microsoft authentication provider with the above registration's Application ID and client secret.
Set "Action to take when request is not authenticated" to "Log in with Microsoft Account".
At this point, I can no longer access my API endpoint without authentication (as expected). I then configured Postman to obtain a token by:
Selecting the Authorization tab.
Setting the Type to "OAuth 2.0".
Clicking "Get New Access Token".
Setting the following values:
Grant Type: Authorization Code
Callback URL: https://<myapp>.azurewebsites.net/.auth/login/microsoftaccount/callback (the same as I entered into my App Registration, above).
Auth URL: https://login.microsoftonline.com/<Directory (tentant) ID>/oauth2/authorize?resource=<Application (client) ID>
Access Token URL: https://login.microsoftonline.com/<Directory (tentant) ID>/oauth2/token?resource=<Application (client) ID>
Client ID: <Application (client) ID>
Client Secret: <Client secret>
Scope: <empty>
State: <empty>
Client Authentication: Send as Basic Auth Header
Clicking the "Request Token" button.
Logging in as myself in the window which pops up. (Only happened the first time; presumably my credentials are being cached somewhere.)
Clicking the "Use Token" button.
Clicking the "Preview Request" button.
When I then click "Send", I get the error above. If I disable authentication or change "Action to takeā€¦" to allow unauthorized requests, it begins working again (but doesn't, of course, require authentication). I've run the JWT that Postman receives through JWT.io and the payload looks reasonable, as far as I can tell:
{
"aud": "<Application (client) ID>",
"iss": "https://login.microsoftonline.com/<Directory (tentant) ID>/v2.0",
"iat": 1558488698,
"nbf": 1558488698,
"exp": 1558492598,
"aio": "<base64? data>",
"azp": "<Application (client) ID>",
"azpacr": "1",
"idp": "live.com",
"name": "Ben Blank",
"oid": "<a GUID I don't recognize>",
"preferred_username": "ben.blank#gmail.com",
"scp": "User.Read",
"sub": "<base64? data>",
"tid": "<Directory (tentant) ID>",
"uti": "<base64? data>",
"ver": "2.0"
}
Can anyone tell me what I've done wrong?
You need to register Postman as a client app in AAD and give it permission to call your API, kind of like here except you will give it permissions to access your API rather than AAD Graph as in the link. Your Postman will need to be configured to use that apps client id and secret to get the token. Right now you are using Postman to ask for your API app to get an access token to itself. Most likely you app is not configured in AAD to call itself! (does not make sense anyway).
You are using Microsoft Account as the Authentication Providers. The way you get the access token is regarding Azure Active Directory, not Microsoft Account.
When you access your function url https://tonytest4.azurewebsites.net/api/HttpTrigger1?name=test, you will redirect to the login page. You will find the url is https://login.live.com/oauth20_authorize.srf?. After entering the correct credential, you will be able to access your function.

Can I get an id_token from Azure AD for my app?

Using the client_credentials flow in Azure AD, I am unable to retrieve an id_token for my app.
I am experimenting with the Azure AD OAuth/OpenID endpoints, and running into some questions.
I create a simple app with minimal config through the Graph API (a beta endpoint, but still). I have removed all the headers and anonymised in code snippets below:
curl -X POST \
https://graph.microsoft.com/beta/applications \
-d '{
"displayName": "App Name",
"passwordCredentials": [
{
"endDateTime": "2299-12-30T23:00:00Z",
"startDateTime": "2019-02-14T20:19:14.686691Z",
"secretText": "<SOME KEY>",
"displayName": "Client Secret"
}
]
}'
In the response from Azure AD, I get an appId:
{
"#odata.context": "https://graph.microsoft.com/beta/$metadata#applications/$entity",
"id": "<SOME GUID>",
"deletedDateTime": null,
"isFallbackPublicClient": null,
"appId": "<SOME GUID>",
...
This is enough for me to be able to retrieve an access_token from the v1 OAuth endpoint:
curl -X POST \
https://login.microsoftonline.com/tenant_id/oauth2/token \
-d 'client_id=appId&client_secret=secretText&grant_type=client_credentials'
Response:
{
"token_type": "Bearer",
"expires_in": "3600",
"ext_expires_in": "3600",
"expires_on": "1550220412",
"not_before": "1550216512",
"resource": "00000002-0000-0000-c000-000000000000",
"access_token": "<JWT access token>"
}
Since I didn't specify a resource in my call, I get the default Graph API resource.
Now, what I also would like to get is an id_token for my app. I have been able to get these tokens from other OpenID providers. However, the OpenID Connect Core spec. gives me reason to think that id_tokens are for end users only, not apps:
"The ID Token is a security token that contains Claims about the Authentication of an End-User by an Authorization Server when using a Client, and potentially other requested Claims"
(From https://openid.net/specs/openid-connect-core-1_0.html#IDToken)
Adding resource=openid to the POST to the token endpoint above won't work, since openid is a scope, not a resource.
Switching to the v2 endpoints, I get access to a scope parameter. I can obtain an access token from there by setting scope=https://graph.microsoft.com/.default, explicitly requesting the access I got by default through the v1 endpoint.
However, setting the scope to for instance scope=https://graph.microsoft.com/.default openid does not give me an id_token for my app, and the access token looks identical to the previous call.
Trying just scope=openid gives me the following error from Azure AD:
AADSTS70011: The provided request must include a 'scope' input parameter. The provided value for the input parameter 'scope' is not valid. The scope openid is not valid.
All this combined leads me to believe that the OpenID providers I have used and have issued id_tokens through the client_credentials flow are breaking the spec, and that id_tokens can only be obtained for end users (using the authorization_code flow gives me an id_token from Azure AD for myself without any issues).
Is this a correct conclusion, or can I force Azure AD to issue id_tokens to apps as well as end users?
An id_token is issued when a user signs-in. Client credentail flows have no user, so no id_token is issued.
you'd need to use a flow like authorization code grant or openID connect to sign a user in. The response will have a id_token.
You cannot use the client credentials flow to get the id_token for app-only, it only returns the access_token.

Resources