Authenticate Azure API Management with OAuth2 using Azure AD - oauth-2.0

I am trying to secure APIM APIs using OAuth2 via AzureAD by reading the article: Protect a web API backend in Azure API Management by using OAuth 2.0 authorization with Azure AD
AzureAPIM - OAuth2
Authorization endpoint URL (v1): https://login.microsoftonline.com/{tenant}/oauth2/authorize
Token endpoint URL (v1): https://login.microsoftonline.com/{tenant}/oauth2/token
Client ID: client-app id
Redirect URI: (deprecated portal): https://xxx-api.portal.azure-api.net/docs/services/auth1/console/oauth2/authorizationcode/callback
AzureAD - backend-app:
scope: Files.All
AzureAD - client-app:
secret key: xxx
Redirect url: ONLY WORK with deprecated portal in APIM (https://xxx-api.portal.azure-api.net/docs/services/auth1/console/oauth2/authorizationcode/callback)
For Demo Conference API, Add Validate JWT policy to Inbound processing where 3a0cf09b- is tenant id and b7c31179- is backend-app application id:
In Developer portal, the authentication to AzureAD is successful with a return token:
However the authorization is failed with calling the API:
Inspecting the received token in jwt.io, I found that the "aud": "00000003-0000-0000-c000-000000000000" is not backend-app application id:
{
"aud": "00000003-0000-0000-c000-000000000000",
"iss": "https://sts.windows.net/3a0cf09b-xxx/",
"app_displayname": "client-app",
"appid": "05a245fb-xxx",
"scp": "Files.Read User.Read profile openid email",
"tenant_region_scope": "OC",
"tid": "3a0cf09b-2952-4673-9ace-0e1bf69ee23a",
"unique_name": "user1#xxx.onmicrosoft.com",
}
API Test HTTP response trace shows the error on validate-jwt:
validate-jwt (-0.138 ms)
{
"message": "JWT Validation Failed: Claim value mismatch: aud=b7c31179-xxx.."
}
Replacing aud by the value in the token 00000003-0000-0000-c000-000000000000 or removing the required-claims in the validate-jwt policy to get it working.
Any idea please?

From your error report, it is indeed a 401 error, that is, your aud does not match the api you want to call, I use the auth code flow to do a simple demonstration for you:
First expose the api of the back-end application and add the client application.
Next,under 'API permissions', give your front-end application access to your backend api:
Under 'API permissions' click on 'Add permission', then click on the 'My APIs' tab.
Find your backend application and select the appropriate scope.
Click 'Add permissions'.
Grant admin consent for your APIs.
Get token:
Parse the token:

It seems you choose v1 endpoint of OAuth2 authorization but not v2 endpoint, so the value of aud in access token should be like b7c31179-xxxx.... but not api://b7c31179-xxxx..... So there are no mistakes in your steps of get access token.
According to some test in my side, the cause of this problem is you did not specify a parameter resource with the value of the backend-app application id when you configure OAuth2.0 in your APIM. The document you refer to also mentions this (I test with not specify this parameter, it shows same problem with yours)
So to solve this problem, please go to your APIM and click "OAuth 2.0" tab, edit the item you created. Add a parameter resource with value of the backend-app application id.
Note: When you add the parameter resource and click "Save" button, please open the item again and check if the "Client secret" box is empty. When I test in my side, the "Client secret" box shows empty after add parameter resource, it may be a bug on that page. If "Client secret" is empty, it might show error message like The request body must contain the following parameter: 'client_assertion' or 'client_secret' when you get the access token in Developer portal.

Related

Add a member to MS Teams using Graph API

I am attempting to add a member to my MS Team using the Graph API and an Azure app token:
Endpoint: https://graph.microsoft.com/v1.0/teams/c924e9b8-*****/members
Body:
'#odata.type':'#microsoft.graph.aadUserConversationMember'
'roles':'[]'
'user#odata.bind':'https://graph.microsoft.com/v1.0/users('41134b16-6f68*****')
When I send this request I am getting:
"code": "InternalServerError"
"message": "Failed to execute request."
I can't seem to find any information on what this error means. Is anyone familiar with this error?
The issue must be due to Web App token generated from Developer portal.
Steps to Resolve:
Check if the required permissions are provided to the app
registration you are using for the webapp i.e.
TeamMember.ReadWriteNonOwnerRole.All with admin consent like below :
Go to Postman>>new_request>>authorization>>Select Oauth2.0 in type>> select Grant type as Client Credential>> fill necessary
details provided below and then click on new access token.
Access Token URL : https://login.microsoftonline.com/my-tenant-id/oauth2/v2.0/token
ClientId: azure ad App reg ID
ClientSecret: Secret generated for the same app
scope: https://graph.microsoft.com/.default
Once the above is done you will be successfully able to do the
operation :

Azure Function AAD Authentication - Client Credentials Flow

I'm trying to figure out how to secure an azure function (service func) that should only be called from another azure function (client func) in the same tenant.
Here's what I've tried in the azure portal:
created a windows function app on a consumption plan
added a hello-world http triggered function with authorization level of "Anonymous"
tested I'm able to call the function anonymously
on the blade for the service func, selected "Authentication"
selected "Add identity provider"
chose "Microsoft"
"Create new app registration"
"Current tenant - Single tenant"
"Require authentication", "HTTP 401"
created a new app registration for the client func, making a note of the client_id and client_secret
I then configured postman to acquire a token from the azure ad (using the only tenant id in play), passing the client_id and client_secret from the app registration of the client func. In the post to the /token endpoint, I gave a grant_type value of "client_credentials".
On posting the request from postman, I received a response containing an access_token. I copied this and pasted into https://jwt.ms to check that all looked ok.
I configured another request in postman to issue a get to the hello-world function. This contained a "Authorization" header with a value of "Bearer " + the access_token received in the previous step.
Despite passing what seems to be a valid access token, the function app (which has no authentication bindings) return a 401 Unauthorized error.
I don't need authorization, just authentication.
Can anyone spot where I went wrong?
I now have this working. I found the following page helpful: Microsoft Doc
Key points:
App roles declared on the app registration of the service app
I didn't manually enter anything into the "Expose an API" page
No authorized client applications listed on the "Expose an API" page
When getting the access token, the scope should be set to the Application ID URI of the target service app registration + "/.default"
API permissions set on the app registration of the client service - these are "Application permissions" NOT "Delegated permissions"
From the function app, select Authentication then edit the identity provider. The value for "Allowed token audiences" needs to be the api://guid value from the "Application ID URI" value of the app registration for the target app service. I noticed that I had problems when using a non-guid value for this

How to connect custom API using own OAuth2 in Microsoft Power Automate?

I've been trying to connect Microsoft Power Automate to my API. My API has a OAuth2 Code Flow.
According to Power Automate, the connector can make a connection to my API. and execute a test. But the problem is that Microsoft sends a Bearer token that was generated by them, and not the one that I gave to them via OAuth2, resuting on my API giving a 401 Error (Invalid Token) as expected.
In the Power Automate Custom Connector page, in the security tab I have the following:
Authentication type
OAuth2.0
OAuth2.0 Settings
Identity Provider: Generic OAuth2
Client ID: SomeValue
ClientSecrect: SomeValue
Authorization URL: mydomain.com/auth/authorize
Token URL: mydomain.com/auth/token
Refresh URL mydomain.com/auth/token
Redirect URL: microsoft-flow.com/redirect (Not the real one)
When Microsoft makes a POST request to mydomain.com/auth/token, I return the following body:
{
access_token: "non JWT token", // simillar to a hash
refresh_token: "non JWT token",
expires_in: 3600
}
The request above is final request that microsoft before accepting as a valid connection. The token that microsoft sends me is a JWT one, not the one I provided.
I've seen some guys using Azure AD authentication within the APP, but I was trying to implement something simillar to other platoforms(e.g Github, Spotify, e.t.c)
So my question is it possible to connect Power Automate to a custom API with using OAuth2? If yes, how to do it?
It's possible.
In addition to the OAuth2.0 Settings you listed, there is another important property Scope which you have missed.
Since your API is protected in Azure AD, so I assume that you have created an Azure AD app for your API and exposed scopes.
After that, you can get the application ID URI (api://{clientId}) for your API.
You should put this value into the "Scope" in Power Automate, like this:
Then this access token will be considered valid by your API.
I've done two steps to fix this problem.
Step 1
Previously my API returned the body with access_token, refresh_token and expires_in, but then I added scope and token_type. Example:
{
access_token: "2346ad27d7568ba9896f1b7da6b5991251debdf2",
refresh_token: "4468e5deabf5e6d0740cd1a77df56f67093ec943",
expires_in: 3600,
scope: "none",
token_type: "Bearer"
}
Step 2
Delete the custom connector and create a new one with the same parameters. When I got to the "Test" section, Power automate finally could make the GET request successfully.
In my case, even if the the API was updated, Power automate was still using its faulty token, so I had to delete that custom connector and create new one.
Conclusion
By updating the API and deleting the old custom connector, I was able to get the connector working.

Possible reasons for invalid_token from AWS Cognito on https://api.amazon.com/auth/o2/tokeninfo

I believe I am missing something with the implicit grant process and access tokens in aws cognito.
To this point:
Have a user pool, with a client app configured for implicit flow and scopes openid, profile, aws.cognito.signin.user.admin
Used a stack overview and the official documentation and older white papers to achieve:
Login process that redirects to aws cognito UI, and back to my app, with tokens and other information in the fragment portion of the URL.
The access_token value parses at jwt.io and signature checks out using the aws jwt tool
Problem:
The recommended step is to "verify that the access token belongs to us" through the tokeninfo api call.
When I attempt to call tokeninfo via javascript code and testing via postman (using: https://api.amazon.com/auth/o2/tokeninfo?access_token=eyJraWQiOiJoVFBa... )
I get the result:
{
"error_description": "The request has an invalid parameter : access_token",
"error": "invalid_token"
}
and an http header:
x-amzn-errortype: InvalidTokenException:http://internal.amazon.com/coral/com.amazon.panda/
Variants I have tried:
I have tried calls directly to the user profile (using Authorization header, and query string and x-amz-access-token header).
I have tried adjust parameter names (error becomes "access_token required" or something like that
I have tried adjusting scopes in the user pool
I have tried adding resource servers (though I am not there yet...)
The redirect after login looks like this:
https://staging.example.com/loginresult.html#id_token=eyJraWQiO<tokenremoved>&access_token=eyJraWQiOiJoVFBa<tokenremoved>&expires_in=3600&token_type=Bearer&state=whateverdevwants
The parsed values of the token (through jwt.io) are:
{
"sub": "5510a27d-ebcb-4883-8680-a66fd0462279",
"token_use": "access",
"scope": "aws.cognito.signin.user.admin openid profile",
"iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_OF5OOfdx0",
"exp": 1519352461,
"iat": 1519348861,
"version": 2,
"jti": "31950a91-e2a5-4060-8c31-977f49802d35",
"client_id": "3iuhnprmod0josge24ogarecfp",
"username": "5510a27d-ebcb-4883-8680-a66fd0462279"
}
Update: As answered below: just don't do this, it is conflating jwt tokens from cognito with whatever "Login With Amazon" was using.
In the example you refer to from Amazon they encode the access token using urllib.quote_plus for example in their PHP example.
Make sure you are URL encoding the access token too in your javascript code with encodeURI.
Also an error may be returned if the token has expired so make sure you verify a newly-minted token. Expiry is 3600 seconds - so make sure the token is less than an hour old.
EDIT
Looks like the documentation for Cognito is very different from the LWA (login with amazon) auth flow. The tokens in the examples you linked to aren't even JWT tokens!
The Cognito documentation here explains how to verify the JWT token.
Checkout the Using ID Tokens and Access Tokens in your Web APIs paragraph.

Using Postman to access OAuth 2.0 Google APIs

I am trying to access Proximity Google API using Postman chrome app. I have followed tutorials on postman and google dev website but I'm still getting 401 error message.
What am I doing?
Step 1 - Enable Proximity API:
In order to use Proximity API, it has to be first enabled in Google Dev console.
Using this tutorial I have enabled support for Proximity API for my project
Step 2 - Get the credentials:
According to this tutorial, I need to get client ID and secret. This is where I am confused. Credentials->Add credentials->OAuth2.0 client ID->select Chrome App radio button (since I am using Postman)->enter last part of Postman's Chrome Web store URL [which is fhbjgbiflinjbdggehcddcbncdddomop]->hit create button These steps will only generate a client ID, not a secret..am I doing something wrong?
From the Google Dev console, one can download an JSON file which has client id, auth URI and Token URI
I downloaded this but this is of little help if I am using Postman. I am guessing this JSON file is something that can be included in a JS application.
Step 3 - Use Postman to test the API
What am I getting?
And, once I click on the debug URL, I see the following screen
Postman will query Google API impersonating a Web Application
Generate an OAuth 2.0 token:
Ensure that the Google APIs are enabled
Create an OAuth 2.0 client ID
Go to Google Console -> API -> OAuth consent screen
Add getpostman.com to the Authorized domains. Click Save.
Go to Google Console -> API -> Credentials
Click 'Create credentials' -> OAuth client ID -> Web application
Name: 'getpostman'
Authorized redirect URIs: https://www.getpostman.com/oauth2/callback
Copy the generated Client ID and Client secret fields for later use
In Postman select Authorization tab and select "OAuth 2.0" type. Click 'Get New Access Token'
Fill the GET NEW ACCESS TOKEN form as following
Token Name: 'Google OAuth getpostman'
Grant Type: 'Authorization Code'
Callback URL: https://www.getpostman.com/oauth2/callback
Auth URL: https://accounts.google.com/o/oauth2/auth
Access Token URL: https://accounts.google.com/o/oauth2/token
Client ID: Client ID generated in the step 2 (e.g., '123456789012-abracadabra1234546789blablabla12.apps.googleusercontent.com')
Client Secret: Client secret generated in the step 2 (e.g., 'ABRACADABRAus1ZMGHvq9R-L')
Scope: see the Google docs for the required OAuth scope (e.g., https://www.googleapis.com/auth/cloud-platform)
State: Empty
Client Authentication: "Send as Basic Auth header"
Click 'Request Token' and 'Use Token'
Set the method, parameters, and body of your request according to the Google docs
The best way I found so far is to go to the Oauth playground here: https://developers.google.com/oauthplayground/
Select the relevant google api category, and then select the scope inside that category in the UI.
Get the authorization code by clicking "authorize API" blue button.
Exchange authorization code for token by clicking the blue button.
Store the OAuth2 token and use it as shown below.
In the HTTP header for the REST API request, add: "Authorization: Bearer ". Here, Authorization is the key, and "Bearer ". For example: "Authorization: Bearer za29.KluqA3vRtZChWfJDabcdefghijklmnopqrstuvwxyz6nAZ0y6ElzDT3yH3MT5"
The current answer is outdated. Here's the up-to-date flow:
The approach outlined here still works (28th of july 2022, confirmed by Jordy)
We will use the YouTube Data API for our example. Make changes accordingly.
Make sure you have enabled your desired API for your project.
Create the OAuth 2.0 Client
Visit https://console.cloud.google.com/apis/credentials
Click on CREATE CREDENTIALS
Select OAuth client ID
For Application Type choose Web Application
Add a name
Add following URI for Authorized redirect URIs
https://oauth.pstmn.io/v1/callback
Click Save
Click on the OAuth client you just generated
In the Topbar click on DOWNLOAD JSON and save the file somewhere on your machine.
We will use the file later to authenticate Postman.
Authorize Postman via OAuth 2.0 Client
In the Auth tab under TYPE choose OAuth 2.0
For values under Configuration Options enter the values found inside the client_secret_[YourClientID].json file we downloaded in step 9
Click on Get New Access Token
Make sure your settings are as follows:
Click here to see the settings
(In addition, multiple scope can be as follows, space-delimited: "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile")
Click on Request Token
A new browser tab/window will open
Once the browser tab opens, login via the appropriate Google account
Accept the consent screen
Done
Ignore the browser message "Not safe" etc. This will be shown until your app has been screened by Google officials. In this case it will always be shown since Postman is the app.
go to https://console.developers.google.com/apis/credentials
create web application credentials.
Postman API Access
use these settings with oauth2 in Postman:
Auth URL = https://accounts.google.com/o/oauth2/auth
Access Token URL = https://accounts.google.com/o/oauth2/token
Choose Scope for the HTTP API
Generate Token
to add Schema use:
SCOPE = https: //www.googleapis.com/auth/admin.directory.userschema
post https: //www.googleapis.com/admin/directory/v1/customer/customer-id/schemas
{
"fields": [
{
"fieldName": "role",
"fieldType": "STRING",
"multiValued": true,
"readAccessType": "ADMINS_AND_SELF"
}
],
"schemaName": "SAML"
}
to patch user use:
SCOPE = https://www.googleapis.com/auth/admin.directory.user
PATCH https://www.googleapis.com/admin/directory/v1/users/admin#email.com
{
"customSchemas": {
"SAML": {
"role": [
{
"value": "arn:aws:iam::123456789123:role/Admin,arn:aws:iam::123456789123:saml-provider/GoogleApps",
"customType": "Admin"
}
]
}
}
}
I figured out that I was not generating Credentials for the right app type.
If you're using Postman to test Google oAuth 2 APIs, select
Credentials -> Add credentials -> OAuth2.0 client ID -> Web Application.
This is an old question, but it has no chosen answer, and I just solved this problem myself. Here's my solution:
Make sure you are set up to work with your Google API in the first place. See Google's list of prerequisites. I was working with Google My Business, so I also went through it's Get Started process.
In the OAuth 2.0 playground, Step 1 requires you to select which API you want to authenticate. Select or input as applicable for your case (in my case for Google My Business, I had to input https://www.googleapis.com/auth/plus.business.manage into the "Input your own scopes" input field). Note: this is the same as what's described in step 6 of the "Make a simple HTTP request" section of the Get Started guide.
Assuming successful authentication, you should get an "Access token" returned in the "Step 1's result" step in the OAuth playground. Copy this token to your clipboard.
Open Postman and open whichever collection you want as necessary.
In Postman, make sure "GET" is selected as the request type, and click on the "Authorization" tab below the request type drop-down.
In the Authorization "TYPE" dropdown menu, select "Bearer Token"
Paste your previously copied "Access Token" which you copied from the OAuth playground into the "Token" field which displays in Postman.
Almost there! To test if things work, put https://mybusiness.googleapis.com/v4/accounts/ into the main URL input bar in Postman and click the send button. You should get a JSON list of accounts back in the response that looks something like the following:
{
"accounts": [
{
"name": "accounts/REDACTED",
"accountName": "REDACTED",
"type": "PERSONAL",
"state": {
"status": "UNVERIFIED"
}
},
{
"name": "accounts/REDACTED",
"accountName": "REDACTED",
"type": "LOCATION_GROUP",
"role": "OWNER",
"state": {
"status": "UNVERIFIED"
},
"permissionLevel": "OWNER_LEVEL"
}
]
}
Google has changed the Access Token URL: https://accounts.google.com/o/oauth2/token.
It now needs to be: https://oauth2.googleapis.com/token
As an addition to the top answer by #DimaTx, don't forget to put checkmark on the "authorize using browser" tickbox, as explained by team postman themselves in github.com/postmanlabs/postman-app-support/issues/7700
This will prevent/solve the “This browser or app may not be secure” result.

Resources