Azure API management - oAuth is not working - azure

I am trying to access a service using Azure API management. I have enabled oAuth authentication on top of the service by using API's > Settings > Security and selexting oAuth 2.0. But Even after making this change, I am able to access the endpoints without providing any tokens. Am I missing anything ?

I did not add the JWT validation policy to pre-authorize requests
To add the policy select Design tab & click on </> icon (for policy code editor) under Inbound Processing & add following code:
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config url="https://login.microsoftonline.com/{aad-tenant}/v2.0/.well-known/openid-configuration" />
<required-claims>
<claim name="aud">
<value>{backend-app-client-id}</value>
</claim>
</required-claims>
</validate-jwt>
After saving it make a new request.

I hope you have configured JWT policy could you please confirm ?
if someone calls your API without a token or with an invalid token? For example, try to call the API without the Authorization header, the call will still go through.
This is because the API Management does not validate the access token, It simply passes the Authorization header to the back-end API.
To pre-Authorize requests, we can use Policy by validating the access tokens of each incoming request. If a request does not have a valid token, API Management blocks it.
reference: https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-protect-backend-with-aad#configure-a-jwt-validation-policy-to-pre-authorize-requests

Related

CORS issue while hitting Azure AD's ROPC endpoint from React Application

My end goal is to authenticate a AD user with his/her username and password credentials only, After research, got to know about ROPC flow, so I created an App Registration, used its tenantID, clientID and such parameters and hit the API with username and password in PostMan. I was successful in getting the tokens. Great.
I need to hit this API from my web application and get tokens.(Getting token is not my objective, but to just authenticate a user). When I try to hit this URL from my React Client, I get CORS error.
What should I do to solve this issue?
I created an App Service, but helpless, couldn't get understanding of what's happening
I tried to reproduce the same in my environment and got the below results:
I generated access token via ROPC Flow using below Parameters:
GET https://login.microsoftonline.com/2f2ebbbc-e970-470e-8ec5-XXXXXXX/oauth2/v2.0/token
client_id:3e3643c5-90af-4af6-af90-XXXXX
client_secret:Client_Secret
grant_type:password
username:user#XXX.onmicrosoft.com
password:*****
scope:scope
To resolve the CORS error, try adding <allowed-headers> tag defined in your CORS policy:
<cors>
<allowed-origins>
<origin>*/</origin>
</allowed-origins>
<allowed-methods preflight-result-max-age="300">
<method>GET</method>
<method>POST</method>
</allowed-methods>
<allowed-headers>
<header>Authorization</header>
</allowed-headers>
</cors>
Check whether you are passing wrong token and check whether you are authorized to perform the action.
If still the issue persists, try not exposing the client_secret and call the Api.
Reference:
Enable Cross-Origin Requests (CORS) | Microsoft Learn

Why aren't the application permissions being added to my MS Graph token?

I'm trying to get a subscription created with the callRecord resource (https://learn.microsoft.com/en-us/graph/api/subscription-post-subscriptions?view=graph-rest-beta&tabs=http)
In the app registration section of the Azure portal, I've created a multi-tenant app with a client secret. That app has permissions for application-level "CallRecords.Read.All" as well as the default delegated "User.Read". The statuses also have a green checkbox for being granted against my organization by an admin.
I am able to get an access token with the following HTTP POST request to https://login.microsoftonline.com/common/oauth2/v2.0/token:
grant_type:authorization_code
scope:https://graph.microsoft.com/.default
client_secret:<client_secret>
client_id:<client_id>
code:<code>
redirect_uri:http://localhost:3000
However, that token is not able to generate a subscription to my callRecord resource. I get a response with this message: "Operation: Create; Exception: [Status Code: Forbidden; Reason: The request is not authorized for this user or application.]"
The message suggests that the app has not been granted admin-level authorization, but in fact it has. This used to work for me. I'm wondering if there has been a regression on the MS Graph side.
Further, when I examine the JWT, I see that the scope is "User.Read profile openid email". There is no mention of the application-level permission (specifically, CallRecords.Read.All)
Thanks.
Because when you use the auth code flow, just the Delegated permission will take effect. So even if you grant the Application permission, the token you got will not include the permission.
From the doc, to call this API Get callRecord, just the Application permission is supported.
To get the token which include the permission, your option is to use the client credential flow.
Note: You need to use <tenant-id> instead of common in this flow.
POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token
client_id=xxxxxxx
&scope=https://graph.microsoft.com/.default
&client_secret=xxxxxxx
&grant_type=client_credentials
Decode the token in https://jwt.io, the roles includes the CallRecords.Read.All permission:

Azure API Managment Not Able to Authorize with azure b2c: Signature Failed

I have configured a backend application (api) and azure apim devportal (client app) in b2c. I have provided access to backend api from client app. I have
used this to configure oauth authentication in azure api management.
I am using authorization code flow. For token validation, I have used inbound policy:
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized" require-expiration-time="true" require-scheme="Bearer" require-signed-tokens="true" clock-skew="0">
<openid-config url="https://<domain>/tenantid/v2.0/.well-known/openid-configuration?p=signinsignup_policy" />
<required-claims>
<claim name="aud">
<value><appid for backend app></value>
</claim>
</required-claims>
</validate-jwt>
While trying from apim developer portal
I am getting below error while using the token received:.
JWT Validation Failed: IDX10501: Signature validation failed. Unable to match keys
I have configured backend api application id as resource and user_impersonation as defaultscope. Decoding token I can see same backend appid as aud. I also tried using appid uri as resource but see same error.
Any help is appreciated.
There are a couple of scenarios that can lead to this error.
Did you check below threads
Azure AD B2C error - IDX10501: Signature validation failed
https://github.com/Azure-Samples/active-directory-dotnet-webapp-openidconnect-aspnetcore/issues/18
If above are not helped: I assume that you are using Custom Policies. While creating Signingkey and encryption you must follow the steps which are described at https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-get-started-custom.
If you skip or modify Key Type/ Key Usage while creating TokenSigning
& TokenEncryption keys there is a chance to get that issue.
Below steps I tried while integrating B2C with API Management. And it is working as expected
Created Web API and Integrated B2C (Followed https://azure.microsoft.com/en-in/resources/samples/active-directory-b2c-dotnet-webapp-and-webapi/)
Integrated Swagger
Created Azure API Management Service
Added API by using "OpenAPI"
Given OpenApi specification URL as https://xxx.azurewebsites.net/Swagger/docs/v1 and created API
While creating API Chosen valid products that are mapped to existing users to test
Navigated to APIM developer portal and tested
While testing added access_token as Authorize header bearer token and tested.
HTH

JWT Validation: Caching JWKS derived from cached discovery document via Azure API Management

I setup caching for discovery endpoint below by wrapping it and caching it via Azure API Management.
https://openid-connect-eu.onelogin.com/oidc/.well-known/openid-configuration
So the new link below does the caching:
https://my.azure-api.net/sso/.well-known/openid-configuration?subscription-key=mykey
Below is policy for token validation:
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Error: expired token or invalid token" require-expiration-time="true" require-scheme="Bearer" require-signed-tokens="true">
<openid-config url="https://my.azure-api.net/sso/.well-known/openid-configuration?subscription-key=mykey" />
<audiences>
<audience>id</audience>
</audiences>
<issuers>
<issuer>https://openid-connect-eu.onelogin.com/oidc</issuer>
</issuers>
</validate-jwt>
My question is that do I need to cache the JWKS link below that is on the discovery document above and used for the validation? If so, how can I cache it?
https://openid-connect-eu.onelogin.com/oidc/certs
You will need to cache the contents of the JWKS endpoint somewhere in the service that you are trying to validate the requesting JWT. A good way to cache these keys is to use a caching library that will cache the keys at the service level for a specified amount of time. The library that I use in my services is called caffeine by Ben Mames and can be found here. Here is a quick example of how you could cache a JWK for 30 minutes:
cache = Caffeine.newBuilder()
.maximumSize(5)
.expireAfterWrite(30, TimeUnit.MINUTES)
.build(k -> jwksMap.get(k));
Your service could then refetch the keys from the endpoint every 30 minutes to refresh the cache.
I do not know the reason why you're caching this document, but both metadata endpoint (https://openid-connect-eu.onelogin.com/oidc/.well-known/openid-configuration) and
key set endpoint (https://openid-connect-eu.onelogin.com/oidc/certs) are fetched by APIM from within validate-jwt policy.
The url on the html body returned is modified and replaced with a new url that is cached via APIM.

Calling the Graph api after SAML2.0 auth. How do I get the Auth token required

Our web aap is authenticating with the Azure AD via SAML2.0 similar to this.
In return we get SAML assertion(SAML token).
But when the user who logs in have more then 150+ groups the response doesn't contain the group information(so that token size doesn’t exceed HTTP header size limits. More info on this)
But what it return is a Graph Api to be hit to get the group information something like https://graph.windows.net/{tenant id}/users/{user id}/getMemberObject.
By going through this
I understand that I need to attach a Auth bearer token with the http request to hit the graph api successfully.
My problem is how do I get the Auth bearer token?
How can I use the SAML token to get the Auth bearer token?
Other useful link - link1 link2
I've only used the non SAML graph API using the ADAL libraries but from the docs it appears the NameID seems to be the basis for requesting an access token for the Graph API:
<Subject>
<NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">m_H3naDei2LNxUmEcWd0BZlNi_jVET1pMLR6iQSuYmo</NameID>
<SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer" />
</Subject>
From this post,
"Here the Client gets a SAML bearer assertion from the SAML Identity
Provider then requests an access token from the Authorisation Server
using the SAML bearer assertion as proof of identity"
and this article states the entire Assertion is used to get the access token, where you:
encode the whole assertion by using base64url encoding before adding
it as part of the POST request
It appears that exchanging a SAML token for a Graph access token is only supported for AD FS, not Azure AD. As per:
This scenario works only when AD FS is the federated identity provider that issued the original SAMLv1 token. You cannot exchange a SAMLv2 token issued by Azure AD for a Microsoft Graph access token.
Source: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-saml-bearer-assertion.
In general, you have to add the OIDC/OAuth stack to your app. As I understand it, this is in addition to your existing SAML authentication implementation. See: https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-token-exchange-saml-oauth

Resources