What is the purpose of claims request parameter on OAuth 2.0? - security

OpenID specification 5.5 explain RP can request claims using claims request parameter. http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter
What is the purpose of this feature?
Is it this feature create security vulnerabilities as user able to set claims?
For example user can modify URL on browser into:
https://op.example.com/authorize?
response_type=code
&client_id=client
&redirect_uri=https://client.example.com
&scope=openid
&claims={“userinfo” : {“sub”: { “value” : “superuser”}} , “id_token” : {“sub”: { “value” : “superuser” }}}
If OP implements this feature, then OP put that claims into id token and user info.

The purpose of this feature is to request claims, possibly with a certain desired value. It does not mean that the RP is able to set claim values. Instead the OP should verify which of the requested claims and values match for the authenticated user and return only those claims that are valid.

Related

Response URI for Azure AD B2C returns 404, custom OpenID identity provider

We're implementing a custom identity provider for Azure AD B2C, using OpenID protocol option, as a generic OpenID Connect.
Everything works as expected until it's time to post the response back to Azure AD B2C using the redirect URI provided. I've found documentation regarding expected structure of this response URL, and what we see in the documentation is identical to what Azure AD B2C specifies when it issues the authentication sequence.
Configured values:
Response type: code
Response mode: form_post
User ID claim: sub
Display name claim: name
When the custom identity provider GETs or POSTs authentication response (code) back to https://REDACTED.b2clogin.com/REDACTED.onmicrosoft.com/oauth2/authresp, the Azure B2C returns 404.
Note that this is not 400, not 401, not 403, not 5xx. It is precisely 404 (not found), with a basic text (non-html) content saying resource not found. This response looks to me very much like a misconfigured API management layer on Azure side, hitting a wrong internal URL.
We're expecting that the URL https://REDACTED.b2clogin.com/REDACTED.onmicrosoft.com/oauth2/authresp actually works. It looks like what the expected Azure AD B2C response endpoint is from documentation, and it is also exactly what Azure AD B2C itself specifies when initiating the OpenID sequence with our custom identity provider web application.
So far we were unable to find the root cause, nor even any useful input beyond raw network request logs (case with Microsoft support was open since 2023-01-23). The last resort could be re-creating the B2C tenant, since this feature seems to work for other people, but that would require migration and significant down time on our end.
SOLUTION: The response to AD B2C authresp endpoint was missing 'nonce' claim (in the id_token payload), and 'state' parameter in the HTTP request. Both values are supplied by AD B2C when initiating authorization. As soon as custom identity provider started properly adding those two values, error 404 went away.
Response should include supplied nonce as a claim inside the id_token payload, and supplied state as HTTP request parameter or query string
https://openid.net/specs/openid-connect-basic-1_0.html
I had the same issue (a 404 error as a result of the /authresp POST from my custom OIDC IdP back to Azure AD B2C using the redirect URI Azure AD B2C had just provided as a query parameter on the /authorize request to my IdP: redirect_uri=https://mytenant.b2login.com/mytenant.onmicrosoft.com/oauth2/authresp
In my case (using an implicit flow), it was about properly handling the "nonce" query parameter on the inbound /authorize request (from Azure AD B2C to my IdP) by ensuring the generated id_token it returned included the nonce as a claim.
In your case (using an authorization code flow...and assuming you also return an id_token based on the "sub" and "name" claims you're returning), your /token endpoint needs to include the nonce inside the id_token...so propagate the nonce (and state) as query parameters along to your /token endpoint via the /authorize to /token redirect method you use.
If a federated IdP doesn't include the nonce as a claim inside the id_token payload that it returns, Azure AD B2C will return a 404 error from the /authresp request.
I don't know why Microsoft chose to return a 404 instead of a more informative "nonce invalid" error message, or at least, a 400 error...perhaps it's for the same security reason a login form doesn't precisely tell you when your password is invalid.
In the OpenID Connect specification, the nonce description (under IDToken) states (bolding is my doing):
String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. If present in the ID Token, Clients MUST verify that the nonce Claim Value is equal to the value of the nonce parameter sent in the Authentication Request. If present in the Authentication Request, Authorization Servers MUST include a nonce Claim in the ID Token with the Claim Value being the nonce value sent in the Authentication Request. Authorization Servers SHOULD perform no other processing on nonce values used. The nonce value is a case sensitive string.
Although the spec indicates a nonce is optional, Microsoft is following best practices by supplying one...and since Azure AD B2C (as the Authorization Server) gets the id_token from the IdP, it requires a federated OIDC IdP to play by the same rule.
In case this helps others, my custom IdP's /.well-known/openid-configuration endpoint returns:
{
"authorization_endpoint": "https://myidp.azurewebsites.net/oauth2/authorize",
"authorization_response_iss_parameter_supported": true,
"claims_parameter_supported": false,
"claims_supported": [
"aud",
"idp",
"iss",
"iat",
"exp",
"nonce",
"s-hash",
"sid",
"sub",
"auth_time",
"email",
"family_name",
"given_name",
"locale",
"name",
"updated_at",
"user_id"
],
"claim_types_supported": ["normal"],
"grant_types_supported": ["implicit"],
"id_token_signing_alg_values_supported": ["RS256"],
"issuer": "https://myidp.azurewebsites.net",
"jwks_uri": "https://myidp.azurewebsites.net/oauth2/jwks",
"response_modes_supported": ["form_post"],
"response_types_supported": ["id_token"],
"scopes_supported": ["openid"]
}
(Yes, my IdP runs on an Azure App server...but, "myidp" isn't my real tenant name.)
p.s. Currently, my IdP is used exclusively in a federation with AzureAD B2C (which acts as the Authorization Server for my client application via the MSAL library), so my IdP simply supports just an implicit flow and three endpoints (/.well-known/openid-configuration, /jwks and /authorize). If it were a general purpose IdP, or allowed direct client requests, it would support other flows (e.g. an authorization code flow), additional scopes (beyond "openid"...e.g. "profile") and additional endpoints (e.g. /token and /userinfo). However, regardless of flow, as long as an id_token is returned, it needs to include the nonce in its payload.
To troubleshoot the issue, I would recommend the following steps:
Verify that the redirect URI you are using is correct and matches
the one specified by Azure AD B2C.
Check that the response type and response mode specified in your
custom identity provider match the values expected by Azure AD B2C.
Verify that the claims you are sending in the response (e.g. "sub"
and "name") match the expected format and values for Azure AD B2C.
Check the network request logs for any additional information that
might help identify the issue.
If possible, try to isolate the issue by testing the authentication
flow with a minimal configuration to determine if the problem is
with your custom identity provider or with Azure AD B2C.
If the issue persists after trying these steps, you may want to consider reaching out to Microsoft support for further assistance.
I tried to reproduce the scenario in my environment:
Make sure the endpoint to which I requested the authorization url
It includes policy and with
redirect URI= https://kavyasarabojub2c.b2clogin.com/kavyasarabojub2c.onmicrosoft.com/oauth2/authresp
User Flow is of SignupSignin and not just Signin
Make sure to include all the required api permissions , importantly make sure to include openid , profile
I Configure idp such that , userId is mapped to oid.
The authorization url must have the policy included .
Here I have B2C_1_SignupSignin policy set for the User flow.
redirect URI= https://kavyasarabojub2c.b2clogin.com/kavyasarabojub2c.onmicrosoft.com/oauth2/authresp
Auth url:
https://kavyasarabojub2c.b2clogin.com/kavyasarabojub2c.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1_newSignupSignin&client_id=xxx&nonce=defaultNonce&redirect_uri=https%3A%2F%2Fxxxb2c.b2clogin.com%2Fxxxb2c.onmicrosoft.com%2Foauth2%2Fauthresp&scope=openid&response_type=id_token&prompt=login
When profile scope is not given I got bad request
But when openid and profile along with Directory.Read.All api permissions are included, the request run successfully.
Note: metadata url must be : https://login.microsoftonline.com/<tenantId>/v2.0/.well-known/openid-configuration
Successfully logged in and got the token containing idp_access_token
Identity provider access token , decoded and got the user claims:

Are the MSAL claims constants available in a package somewhere?

I've moved my authentication to MSAL and I want to examine my claims on the client side to see, for example, the object ID that I have in Azure B2C (and thus, give my client an identity).
On the server, the objectId claim appears to be returned as:
{http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: 63fd3d89-26ff-4934-907c-5e6c9da07c45}
The URI "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" is a known claim and can be accessed using Claims.Name and I can use a statement like this to extract the objectId from the claims:
Guid userId = new(this.User.FindFirstValue(ClaimTypes.NameIdentifier));
But on the client, the objectId claim is returned using the 'oid' URI and I can't use the same kind of pre-defined claims that I can on the server.
Obviously I can define these as constants in a shared module, but I can't be the only one trying to parse claims from the client side. Is there an analog of 'ClaimTypes' for MSAL on the client side?
I was searching for the same thing and found the ClaimConstants.ObjectId (see here) to match the oid claim type (http://schemas.microsoft.com/identity/claims/objectidentifier).
Guid userId = new(this.User.FindFirstValue(ClaimConstants.ObjectId));
It's part of the Microsoft.Identity.Web package.

Using JSON Web Tokens (JWT) with Azure Functions (WITHOUT using Active Directory)

I am sure someone out there has already done this, but I have yet to find any documentation with regard to the Microsoft implementation of JWT. The official documentation from Microsoft for their JWT library is basically an empty page, see:
https://learn.microsoft.com/en-us/dotnet/framework/security/json-web-token-handler-api-reference
So, here is what I (and I am sure many others) would like to accomplish:
Definition: User ID = The username or email address used to log into a system.
AUTHENTICATION:
A user logs in. The user fills in web form and the system sends (via HTTPS POST) the users ID and password (hashed) to the server in order to authenticate / validate the user.
Server Authenticates user. The users ID and password are checked against the values saved in the database and if NOT valid, an invalid login response is returned to the caller.
Create a JWT Token - ???? No documentation available!
Return the JWT token to the caller - ???? - I assume in a header? via JSON, not sure -- again - no documentation.
Given the code below, can anyone provide a code example for steps 3 and 4?
[FunctionName( "authenticate" )]
public static async Task<HttpResponseMessage> Run( [HttpTrigger( AuthorizationLevel.Anonymous, "get", "post", Route = null )]HttpRequestMessage req, TraceWriter log )
{
// Step 1 - Get user ID and password from POST data
/*
* Step 2 - Verify user ID and password (compare against DB values)
* If user ID or password is not valid, return Invalid User response
*/
// Step 3 - Create JWT token - ????
// Step 4 - Return JWT token - ????
}
AUTHORIZATION:
Assuming the user was authenticated and now has a JWT token (I am assuming the JWT token is saved in the users session; if someone wants to provide more info, please do):
A POST request is made to an Azure Function to do something (like get a users birth date). The JWT token obtained above is loaded (from the POST data or a header - does it matter?) along with any other data required by the function.
The JWT token is validated - ???? No documentation available!
If the JWT token is NOT valid, a BadRequest response is returned by the function.
If the JWT token is valid, the function uses the data passed to it to process and issue a response.
Given the code below, can anyone provide a code example for steps 1 and 2?
[FunctionName( "do_something" )]
public static async Task<HttpResponseMessage> Run( [HttpTrigger( AuthorizationLevel.Anonymous, "get", "post", Route = null )]HttpRequestMessage req, TraceWriter log )
{
// Step 1 - Get JWT token (from POST data or headers?)
// Step 2 - Validate the JWT token - ???
// Step 3 - If JWT token is not valid, return BadRequest response
// Step 4 - Process the request and return data as JSON
}
Any and all information would really help those of us (me) understand how to use JWT with Azure (anonymous) functions in order to build a "secure" REST API.
Thanks in advance.
Any and all information would really help those of us (me) understand how to use JWT with Azure (anonymous) functions in order to build a "secure" REST API.
Per my understanding, you could use the related library in your azure function code to generate / validate the JWT token. Here are some tutorials, you could refer to them:
Create and Consume JWT Tokens in C#.
Jwt.Net, a JWT (JSON Web Token) implementation for .NET
JWT Authentication for Asp.Net Web Api
Moreover, you could leverage App Service Authentication / Authorization to configure the function app level Authentication / Authorization. You could go to your Function App Settings, click "NETWORKING > Authentication / Authorization" under the Platform features tab. Enable App Service Authentication and choose Allow Anonymous requests (no action) as follows:
You could create a HttpTrigger function with anonymous accessing for user logging and return the JWT token if the user exists. For the protected REST APIs, you could follow the code sample below:
if(System.Security.Claims.ClaimsPrincipal.Current.Identity.IsAuthenticated)
{
//TODO: retrieve the username claim
return req.CreateResponse(HttpStatusCode.OK,(System.Security.Claims.ClaimsPrincipal.Current.Identity as ClaimsIdentity).Claims.Select(c => new { key = c.Type, value = c.Value }),"application/json");
}
else
{
return req.CreateResponse(HttpStatusCode.Unauthorized,"Access Denied!");
}
For generating the JWT token used in App Service Authentication, you could follow How to: Use custom authentication for your application and the code under custom API controller CustomAuthController from adrian hall's book about Custom Authentication to create the JWT token.
UPDATE:
For the custom authentication approach under App Service Authentication, I just want op to leverage the authentication / Authorization provided by EasyAuth. I have did some test for this approach and found it could work on my side. Op could send the username and password to the HttpTrigger for authentication, then the HttpTrigger backend need to validate the user info, and use Microsoft.Azure.Mobile.Server.Login package for issuing App Service Authentication token to the client, then the client could retrieve the token from the AuthenticationToken property. The subsequent requests against the protected APIs could look like as follows:
https://<your-funapp-name>.azurewebsites.net/api/<httpTrigger-functionName>
Header: x-zumo-auth:<AuthenticationToken>
NOTE:
For this approach, the related HttpTrigger functions need to allow anonymous accessing and the App Service Authentication also needs to choose Allow Anonymous requests (no action). Otherwise, the App Service Authentication and function level authentication would both validate the request. For the protected APIs, op needs to manually add the System.Security.Claims.ClaimsPrincipal.Current.Identity.IsAuthenticated checking.
Try this: https://liftcodeplay.com/2017/11/25/validating-auth0-jwt-tokens-in-azure-functions-aka-how-to-use-auth0-with-azure-functions/
I successfully made it work using this guide. It took awhile due to nuget versions.
Follow that guide properly and use the following nuget versions
IdentityModel.Protocols (2.1.4)
IdentityModel.Protocols.OpenIdConenct (2.1.4)
IdentityModel.Tokens.Jwt (5.1.4)
Oh and, the guide tells you to write your AUDIENCE as your api link, don't. You'll get unauthorized error. Just write the name of your api, e.g. myapi
If you get error about System.http.formatting not being loaded when running the function, try to reinstall NET.Sdk.Functions and ignore the warning about AspNet.WebApi.Client being restored using .NETFramework. And restart visual studio.
What you're describing is something that you should be able to do yourself by doing a little bit of research. To address your specific questions:
Create a JWT Token - ???? No documentation available!
The link Bruce gave you gives a nice example for how to create a JWT: https://www.codeproject.com/Tips/1208535/Create-And-Consume-JWT-Tokens-in-csharp
Return the JWT token to the caller - ???? - I assume in a header? via JSON, not sure -- again - no documentation.
There's no documentation because you're basically inventing your own protocol. That means how you do it is entirely up to you and your application requirements. If it's a login action, it might make sense to return it as part of the HTTP response payload. Just make sure that you're using HTTPS so that the token stays protected over the wire.
A POST request is made to an Azure Function to do something (like get a users birth date). The JWT token obtained above is loaded (from the POST data or a header - does it matter?) along with any other data required by the function.
How you send the token is, again, entirely up to you. Most platforms use the HTTP Authorization request header, but you don't have to if you don't want to.
The JWT token is validated - ???? No documentation available!
Use the ValidateToken method of the JwtSecurityTokenHandler (see the previous link for how to get the JwtSecurityTokenHandler). Docs here: https://msdn.microsoft.com/en-us/library/dn451155(v=vs.114).aspx.
I created an Azure Functions input binding for JWT Token Validation. You can use this as an extra parameter with the [JwtBinding] attribute. See https://hexmaster.nl/posts/az-func-jwt-validator-binding/ for source and NuGet package information.
Basically Azure Functions built on top of ASP.NET Core. By making some dependency injection tricks you could add your own authentication and policy-based authorization. I created demo solution with JWT authentication just for fun, beware to use it on production.

401 unauthorize exception for multitenant web api

Need help in authenticating the token request from any client application to WEB API. We have registered our web API has multi-tenant application in Azure AAD. My client application which has been registered in different tenant was able to get Access token from AAD.while making Http request to our endpoint with passing the access token part of request header, we are receiving 401 unauthorized exception. I found reason while browsing for multi tenant scenario is to disable ValidateIssuer and have custom handler.
• Is there any custom handler on implementing for WindowsAzureActiveDirectoryBearerAuthentication. I see people are using OpenIDConnect. But for WEB API, we are using WindowsAzureActiveDirectoryBearerAuthentication i.e Is there any equivalent Event for validation of access token in UseWindowsAzureActiveDirectoryBearerAuthentication and tell user is authenticated ?.
• Is there any better standard of validation of access token and tell user is valid user ?.
• Can we get the claims of user by passing bearer token to WEBAPI Authorize filter ?. or will httprequest object claims gets user information like given name, tenant name, object ID (esp. localhost debugging scenario also.), If we can get those information, we can have our own logic of validation.
Please let us know whether this approach is best practice for authenticating a user.
You could implement a custom issuer validator and assign it to the IssuerValidator property. This is useful when you can't specify a predefined list of issuers in configuration and need some runtime logic to determine if you trust the issuer presented in the token:
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
IssuerValidator = (issuer, token, tvp) =>
{
if (db.Issuers.FirstOrDefault(b => (b.Issuer == issuer)) == null)
return issuer;
else
throw new SecurityTokenInvalidIssuerException("Invalid issuer");
}
}
You could decode the access token to get basic user information like family_name/given_name , but you can only get that by using user identity to acquire the access token .

Web API 2 OWIN Bearer Token purpose of cookie?

I am trying to understand the new OWIN Bearer Token authentication process in the Single Page App template in MVC 5. Please correct me if I'm wrong, for the OAuth password client authentication flow, Bearer Token authentication works by checking the http authorization request header for the Bearer access token code to see if a request is authenticated, it doesn't rely on cookie to check if a particular request is authenticated.
According to this post:
OWIN Bearer Token Authentication with Web API Sample
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
using (IdentityManager identityManager = _identityManagerFactory.CreateStoreManager())
{
if (!await identityManager.Passwords.CheckPasswordAsync(context.UserName, context.Password))
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
string userId = await identityManager.Logins.GetUserIdForLocalLoginAsync(context.UserName);
IEnumerable<Claim> claims = await GetClaimsAsync(identityManager, userId);
ClaimsIdentity oAuthIdentity = CreateIdentity(identityManager, claims,
context.Options.AuthenticationType);
ClaimsIdentity cookiesIdentity = CreateIdentity(identityManager, claims,
_cookieOptions.AuthenticationType);
AuthenticationProperties properties = await CreatePropertiesAsync(identityManager, userId);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
}
The GrantReourceOwnerCredentials function not only compose the ticket with this line: context.Validated(ticket); but it also compose a cookie identity and set it to the cookie with this line: context.Request.Context.Authentication.SignIn(cookiesIdentity);
So my questions are, what is the exact purpose of the cookie in this function? Shouldn't the AuthenticationTicket be good enough for authentication purpose?
In the SPA template there are actually two separate authentication mechanisms enabled- cookie authentication and token authentication. This enables authentication of both MVC and Web API controller actions, but requires some additional setup.
If you look in the WebApiConfig.Register method you'll see this line of code:
config.SuppressDefaultHostAuthentication();
That tells Web API to ignore cookie authentication, which avoids a host of problems which are explained in the link you posted in your question:
"...the SPA template enables application cookie middleware as active mode as well in order to enable other scenarios like MVC authentication. So Web API will still be authenticated if the request has session cookie but without a bearer token. That’s probably not what you want as you would be venerable to CSRF attacks for your APIs. Another negative impact is that if request is unauthorized, both middleware components will apply challenges to it. The cookie middleware will alter the 401 response to a 302 to redirect to the login page. That is also not what you want in a Web API request."
So now with the call to config.SuppressDefaultHostAuthentication() Web API calls that require authorization will ignore the cookie that is automatically sent along with the request and look for an Authorization header that begins with "Bearer". MVC controllers will continue to use cookie authentication and are ignorant of the token authentication mechanism as it's not a very good fit for web page authentication to begin with.
The existence of the cookie also left me puzzled, since it clearly is not necessary in a bearer token authentication scenario... In this post the author dissects the individual accounts template, and has the following to say about the cookie:
The method also sets an application cookie. I don’t see a good reason for that.
My guess is that the authors of the template wanted to show examples of different kinds of authentication logic, and in this particular case they wanted to show how the authentication information could be stored in both the bearer token authentication JSON payload, as well as in a standard authentication cookie.
The fact that the JSON authentication payload is set to also include an additional (unnecessary) unencrypted property (the user id), in addition to the encrypted ticket, seems to support this theory:
var properties = CreateProperties(user.UserName);
var ticket = new AuthenticationTicket(oAuthIdentity, properties);
It seems that the authors of the template wanted to provide some useful examples, rather than the bare minimum needed to achieve bearer token authentication. This is also mentioned in the linked post above.
The cookie has one important purpose. Its value contains the bearer token which can be extracted by client-side javascript on your pages. This means that if the user hits F5 or refreshes the page, the cookie will typically persist. Your client-side javascript can then grab the bearer token from the cookie when the page reloads.

Resources