B2C OAuth2 API error: Signature validation failed. Unable to resolve SecurityKeyIdentifier: 'SecurityKeyIdentifier - azure-ad-b2c

I have spent quite a bit of time getting our .NET MVC web application to integrate with Azure Active Directory B2C, with reasonable success, using a custom profile to allow users of other Azure Active Directories to log in to us.
Now I want to incorporate an API, roughly following this process:
https://github.com/Azure-Samples/active-directory-b2c-dotnet-webapp-and-webapi
I say roughly because I'm trying to fit this functionality into an application that's already been under development for several months.
I'm using Postman to hit this URL a and get a bearer token:
https://login.microsoftonline.com/ourtenant.onmicrosoft.com/oauth2/token
I use the grant_type=client_credentials, and the client_id and client_secret specified in Active Directory (added in the the "not-B2C" App registrations blade because apparently B2C doesn't yet support the client_credentials flow)
It appears to work fine and I get a response like this:
{
"token_type": "Bearer",
"expires_in": "3599",
"ext_expires_in": "0",
"expires_on": "1513906161",
"not_before": "1513902261",
"resource": "00000002-0000-0000-c000-000000000000",
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ing0Nzh4eU9wbHNNMUg3TlhrN1N4MTd4MXVwYyIsImtpZCI6Ing0Nzh4eU9wbHNNMUg3TlhrN1N4MTd4MXVwYyJ9.eyJhdWQiOiIwMDAwMDAwMi0wMDAwLTAwMDAtYzAwMC0wMDAwMDAwMDAwMDAiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83YjY1ZDY0NC0xNDM0LTQxZDQtYTFhMC04MjVlZjgwOTAyZDMvIiwiaWF0IjoxNTEzOTAyMjYxLCJuYmYiOjE1MTM5MDIyNjEsImV4cCI6MTUxMzkwNjE2MSwiYWlvIjoiWTJOZ1lKaTJWbkhKTXQwNUcrZmMrL2pFNmRQLzdRQT0iLCJhcHBpZCI6IjZkZmVkNGVkLTU2ZDktNDQ5Ny04M2JhLTkzOWJmNGI3OGUyNSIsImFwcGlkYWNyIjoiMSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzdiNjVkNjQ0LTE0MzQtNDFkNC1hMWEwLTgyNWVmODA5MDJkMy8iLCJvaWQiOiIxYTYxNGM5Yy00Nzc5LTQ2OTctOThjNC05OWNlZTJlZTVkY2IiLCJzdWIiOiIxYTYxNGM5Yy00Nzc5LTQ2OTctOThjNC05OWNlZTJlZTVkY2IiLCJ0ZW5hbnRfcmVnaW9uX3Njb3BlIjoiTkEiLCJ0aWQiOiI3YjY1ZDY0NC0xNDM0LTQxZDQtYTFhMC04MjVlZjgwOTAyZDMiLCJ1dGkiOiJjV2lzVmxDRDEwdW9Ra3BHbWRBdkFBIiwidmVyIjoiMS4wIn0.BiXHI5Sp0t2k_npJYdWjclSXGOMbxniR8G1ifOCNUuiNUZRFG6DsbIqkJEBXSFFUxQpvtGkBaI5oF2u4oJ5Ed37thh_gOLJ1TKBaubGusv7vgUVoIk9A5F8H_HeX57zyRR2XU3czdSC4uZC_XpVwV7eT4-Z4bNooL0WJi1ZNx6ZFBC4qktNf7yifc7-iAEEDTWj3clwA81RJwAe9YbUMI3q640sNg8QlrZDiKFzuEuFocHces0bAYSyfLu5cwDw2wvJwQzYEMahjQ3V7RXpqg-YktsUoSTkLOHm7QNrM2Pko8ZAye58O-nTv1gD5yYDZ8st74x4MUHhNZhaR44byjw"
}
When I use this bearer token in the Authorization header an API call, I get the response:
{"Message":"Authorization has been denied for this request."}
I switched on diagnostic tracing and found this in the output:
Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationMiddleware Error: 0 : Authentication failed
System.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10500: Signature validation failed. Unable to resolve SecurityKeyIdentifier: 'SecurityKeyIdentifier
(
IsReadOnly = False,
Count = 2,
Clause[0] = X509ThumbprintKeyIdentifierClause(Hash = 0xC78EFCC723A996C3351FB35793B4B1D7BC75BA97),
Clause[1] = System.IdentityModel.Tokens.NamedKeySecurityKeyIdentifierClause
)
',
token: '{"typ":"JWT","alg":"RS256","x5t":"x478xyOplsM1H7NXk7Sx17x1upc","kid":"x478xyOplsM1H7NXk7Sx17x1upc"}.{"aud":"00000002-0000-0000-c000-000000000000","iss":"https://sts.windows.net/7b65d644-1434-41d4-a1a0-825ef80902d3/","iat":1513901664,"nbf":1513901664,"exp":1513905564,"aio":"Y2NgYPg7bbbRmu/aXjwejXZs73e5AgA=","appid":"6dfed4ed-56d9-4497-83ba-939bf4b78e25","appidacr":"1","idp":"https://sts.windows.net/7b65d644-1434-41d4-a1a0-825ef80902d3/","oid":"1a614c9c-4779-4697-98c4-99cee2ee5dcb","sub":"1a614c9c-4779-4697-98c4-99cee2ee5dcb","tenant_region_scope":"NA","tid":"7b65d644-1434-41d4-a1a0-825ef80902d3","uti":"5nMOpv6eok60JyzWwksuAA","ver":"1.0"}
RawData: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ing0Nzh4eU9wbHNNMUg3TlhrN1N4MTd4MXVwYyIsImtpZCI6Ing0Nzh4eU9wbHNNMUg3TlhrN1N4MTd4MXVwYyJ9.eyJhdWQiOiIwMDAwMDAwMi0wMDAwLTAwMDAtYzAwMC0wMDAwMDAwMDAwMDAiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83YjY1ZDY0NC0xNDM0LTQxZDQtYTFhMC04MjVlZjgwOTAyZDMvIiwiaWF0IjoxNTEzOTAxNjY0LCJuYmYiOjE1MTM5MDE2NjQsImV4cCI6MTUxMzkwNTU2NCwiYWlvIjoiWTJOZ1lQZzdiYmJSbXUvYVhqd2VqWFpzNzNlNUFnQT0iLCJhcHBpZCI6IjZkZmVkNGVkLTU2ZDktNDQ5Ny04M2JhLTkzOWJmNGI3OGUyNSIsImFwcGlkYWNyIjoiMSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzdiNjVkNjQ0LTE0MzQtNDFkNC1hMWEwLTgyNWVmODA5MDJkMy8iLCJvaWQiOiIxYTYxNGM5Yy00Nzc5LTQ2OTctOThjNC05OWNlZTJlZTVkY2IiLCJzdWIiOiIxYTYxNGM5Yy00Nzc5LTQ2OTctOThjNC05OWNlZTJlZTVkY2IiLCJ0ZW5hbnRfcmVnaW9uX3Njb3BlIjoiTkEiLCJ0aWQiOiI3YjY1ZDY0NC0xNDM0LTQxZDQtYTFhMC04MjVlZjgwOTAyZDMiLCJ1dGkiOiI1bk1PcHY2ZW9rNjBKeXpXd2tzdUFBIiwidmVyIjoiMS4wIn0.mPzogfR2ndo89P-qWIypdPjrrBb0uEOO0Fo-H164C4Rm21zFQpkwVSFe-NP4MtvMnB5fJdhzGxzPDACFHBiQi7k7ZZVGv5bWaIbhGlPmKCQ1j6XaweYp7pm66R-RIsokZvR87nJ4ZkvYJIkuxnXPjChC-3FjsLDf43FKcByDPvvJKpVj48JW9N79vq77HQ2w8bnq172zOUflxGbuC2nDiwzkgWQiFboL-H3LLUxHqZHeE46u7pDSOrE3DSY1F5aPqBq1IDCg6ELcBcaLN27509oAH2rghkvXjHWOs9Nw3tszVoza7CpEGV7fjtSGN874GV_vx-ziqIOf1EgSBPEH6Q'.
at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateToken(String securityToken, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at Microsoft.Owin.Security.Jwt.JwtFormat.Unprotect(String protectedText)
at Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationHandler.<AuthenticateCoreAsync>d__0.MoveNext()
What am I missing?

The sample that you linked shows you how to secure and call a web API using Azure AD B2C. It seems like you are trying to obtain an Azure AD token, and then trying to use that to sign into an API that is secured using Azure AD B2C.
While client credentials is not supported in Azure AD B2C, it doesn't seem like you need the client credential flow. Client credential flow is used for an API to API call. If you want to call an API from the app that the users are signing into, you can use access tokens. Check out this document: https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-access-tokens

Related

Bypass Azure AD SAML

I got SAML setup on my AD and I have the private and certificate PEMs along with the certificate and metadata and I want to know if it's possible to bypass the login from API? I'm developing a Node.JS API which I want to make requests to the server behind the SAML login but I need to bypass it with what I got.
Maybe a way to generate a token from Azure's API (to use as bearer authorization) would work like how you do it with OAuth?
I'm not asking for any other solution (like whitelisting etc.), I just need it to be token / API based
To bypass azure ad , you may chose for the On behalf flow.
For single-page apps (SPAs), here we pass an access token to a middle-tier confidential client to perform OBO flows instead.
This will only work, if the respective permissions (scope grants) are
already granted when you try to get an access token using the
on-behalf of flow.
Here API A authenticates to the Microsoft identity platform token
issuance endpoint and requests a token to access API B.
https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token
with grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
client_id=xxx
&client_secret=saxx1s
&scope=https://graph.microsoft.com/user.read+offline_access
&requested_token_use=on_behalf_of
Here we need to expose api and here I am giving user.read
And exposed api
The response has access token , refresh token
{
"token_type": "Bearer",
"scope": "https://graph.microsoft.com/user.read",
"expires_in": 3269,
"ext_expires_in": 0,
"access_token": "xx",
"refresh_token": "xxxx"
}
Please check Microsoft identity platform and OAuth2.0 On-Behalf-Of flow - Microsoft Entra | Microsoft Learn
Reference : how-to-use-azure-ad-access-token-to-bypass-microsoft-online-login

Using Azure OAuth2 token to call Azure DevOps API (user_impersonation scope)

I have created and registered an Application in Azure AD, which has multiple API permissions configured, among them Azure DevOps, the only available permission, user_impersonation.
I have successfully obtained an OAuth2 token via the full code flow, with requested scope of https://app.vssps.visualstudio.com/user_impersonation.
The access token is JWT, and I have decoded it:
{ :tid "bd4570a0-5905-40fb-8ebe-58479aecbc71",
:rh "0.AS8AoHBFvQVZ-0COvlhHmuy8cb1hUgm2ml5JrS8cjDMq-ZsvAAc.",
:given_name "R",
:scp "user_impersonation",
:email "rl#protonmail.com",
:aud "https://app.vssps.visualstudio.com",
:sub "h4S-EF9-NYufBaSwlUueuOTJbVnzAtXSeWg7R0_4IwQ",
:iss "https://sts.windows.net/bd4570a0-5905-40fb-8ebe-58479aecbc71/",
:name "R L",
:idp "live.com",
:exp 1638456612,
:uti "iHKHjhyHUEGpz4FQ37swAQ",
:aio "AWQAm/8TAAAA5hRQi967V5w85GNwWSWaJOVjEBs+FTyoWMdjgUQm6qoQoxjNDu1AuAHJuC9cJhWKmu89zXj2z5vNFiytM+wfKuoGrKDDZNAJSXdbWuKau+lTNOyPaugymzVO6q7ODR8W",
:family_name "L",
:amr ["pwd" "mfa"],
:nbf 1638452281,
:oid "3e18766c-8a5f-49be-9dcf-2c9edf03f6b1",
:ipaddr "188.230.144.31",
:appid "095261bd-9ab6-495e-ad2f-1c8c332af99b",
:unique_name "live.com#rl#protonmail.com",
:wids ["62e90394-69f5-4237-9190-012177145e10" "b79fbf4d-3ef9-4689-8143-76b194e85509"],
:appidacr "1",
:acr "1",
:ver "1.0",
:puid "1003200178C49F6B",
:iat 1638452281,
:altsecid "1:live.com:0003BFFD3D75E35F"}
So far so good. The important part here is aud that is the intended target for token which is "https://app.vssps.visualstudio.com" which is Azure DevOps service/resource.
I try to use is as a bearer token when calling Azure DevOps service:
e.g.
GET https://app.vssps.visualstudio.com/_apis/profile/profiles/me?api-version=6.1-preview.3
with header Authorization value Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1N...
, I always get back a redirect to https://app.vssps.visualstudio.com/_signin?realm=app.vssps.visualstudio.com....., as if I wasn't authenticated.
Is there some step I am missing here? I have successfully called this endpoint with other types of authentication.

Azure AD B2C Custom policy, how to put application scopes in access token

Here's the configuration for the Azure AD B2C, create two applications: web and api. added two scopes read and write to the api scope. configure web application to web application. tested with the built-in user flows e.g. sign up sign in. run the flow for the web app, get the access token, scopes are in the token.
now create a custom policy to use multitenants to authenticate the users with Azure AD. created a custom signup/in policy. run the policy, got the access token by specifying the api scopes in the access token, however the return token does not contain the scope claims. my question is how to configure the custom policy to have the api scopes in the access token?
When you run the custom policy, it will only return an ID token rather than access token.
So your scope claims won't be included in the ID token.
You should refer to Request an access token in Azure Active Directory B2C.
After you have Added a web API application to your Azure Active Directory B2C tenant, use authorization code flow to get the access token.
GET https://<tenant-name>.b2clogin.com/tfp/<tenant-name>.onmicrosoft.com/<policy-name>/oauth2/v2.0/authorize?
client_id=<application-ID>
&nonce=anyRandomValue
&redirect_uri=https://jwt.ms
&scope=https://<tenant-name>.onmicrosoft.com/api/read
&response_type=code
The response with the authorization code should be similar to this example:
https://jwt.ms/?code=eyJraWQiOiJjcGltY29yZV8wOTI1MjAxNSIsInZlciI6IjEuMC...
After successfully receiving the authorization code, you can use it to request an access token:
POST <tenant-name>.onmicrosoft.com/oauth2/v2.0/token?p=<policy-name> HTTP/1.1
Host: <tenant-name>.b2clogin.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&client_id=<application-ID>
&scope=https://<tenant-name>.onmicrosoft.com/api/read
&code=eyJraWQiOiJjcGltY29yZV8wOTI1MjAxNSIsInZlciI6IjEuMC...
&redirect_uri=https://jwt.ms
&client_secret=2hMG2-_:y12n10vwH...
The response:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrN...",
"token_type": "Bearer",
"not_before": 1549647431,
"expires_in": 3600,
"expires_on": 1549651031,
"resource": "f2a76e08-93f2-4350-833c-965c02483b11",
"profile_info": "eyJ2ZXIiOiIxLjAiLCJ0aWQiOiJjNjRhNGY3ZC0zMDkxLTRjNzMtYTcyMi1hM2YwNjk0Z..."
}
See details here.

Getting the access token for Microsoft Graph API

I'm trying to get the access token for the Microsoft Graph API in order to access a SharePoint document library. My application is a windows service, hence I'm following the procedure described here.
But when I try to get the access token, the response that I get doesn't have the scope value. Below is my response:
{
"token_type": "Bearer",
"expires_in": "3600",
"expires_on":"1492452559",
"not_before": "1492448659",
"resource": "https://graph.microsoft.com",
"access_token": "Token"
}
Because of this when I try to query the Graph API with this access token, I'm getting an error saying: Either scp or roles claim need to be present in the token
Can someone please help me on how to get this working? Thanks in advance.
That seems your client application hasn't set the appropriate app permissions when using client credential flow , below is an illustration of application permissions section in Azure AD classic portal. Please select appropriate permissions needed and retry :
And in addition , when using client credential flow to get the access token , you could check the roles claims in access token(that is the way to check the app permission, not in token response) , using a tool like http://jwt.calebb.net/ to decode the access token and check the app permissions :

How to add simple authentication to azure mobile/web apps with Azure Active Directory?

My goal is to secure my mobile app custom API methods and use then via httpclient(c#).
As a part of the testing I used Postman to request a token and use it to access the resource.
I will explain with the vanilla template that comes when creating a new Mobile App.
Create a new mobile app.
Publish it to Azure.
Open it on Azure portal, Go to Settings blade. Find Authentication / Authorization.
Turn App Service Authentication to On and select Azure Active Directory>Express>Create a new AD app.
Open Active Directory (Management Portal), pick the directory for your account.
Select Applications, the one you just created.
Go to Configure tab and copy the ClientId, Create a Key, copy it too.
Click on View EndPoints at the bottom and copy the OAuth 2.0 Token EndpointOauth2.0 Token
Now open the mobile app project and decorate the controller/method you want to project with [Authorize].
You should be all set with the setup.
Now open your favorite client, in my case Postman and
Step 1: Request a token
Method: POST
URL : {Oauth TokenEndPoint from Step. 8}
grant_type : client_credentials
client_id : {one copied from AD section in Step. 7}
client_secret : {one copied from AD section in Step. 7}
resource : {one copied from AD section in Step. 7}
You will receive a response like this
"token_type": "Bearer",
"expires_in": "3600",
"expires_on": "1453151213",
"not_before": "1453147313",
"resource": "yyyyyyyyyyyyyyyyyy",
"access_token": "xxxxxxxxxxxxxxxxxxx"
Now copy the access_token and use it in your request to the mobile app.
Method: Get
URL : https://MyMobileApp.azurewebsites.net/api/values?ZUMO-API-VERSION=2.0.0
Headers : Authorization : Bearer xxxxxxxxxxxxxxxxxxx
In case if you run into any issues, here is a key step. Go to Azure portal and turn on Application Logging, Detailed error messages, Failed request tracking under Diagnostics logs (Settings blade).
Now you can see whats happening and much more detailed logging under Log Stream(Tools blade).

Resources