Codeless API Authorization (JWT validation) using Azure API management
I have another post here on how to offload caching to Azure API management. In this post, I am going to demonstrate the security feature.
The first step is creating an Azure API management service. There is no specific parameter here beside the email which is going to be used to receive emails on subscription, etc. Creating this service for Pricing tiers other than Consumption usually takes longer than usual (over 20 mins!). Consumption model costs less and it's quicker to provision but is excluding some features like developer portal.
When the resource is created select the APIs and add an API using OpenAPI.
Here I am going to use the same API that I have used for my other post. The OpenAPI json is on https://catalogservicetest.azurewebsites.net/swagger/v1/swagger.json
After creating the API, I need to set my backend.
Let's just give our API a test.
While it would work from the API management test panel but if we try our API in postman it would get rejected with 401:
The reason is clearly mentioned in the returned message: "missing subscription key". For this post I am going to simply disable this. If you are interested you can see how I am using it in my other post. Head back to the API Settings tab and remove the Subscription Required checkbox and save.
Adding JWT validation
Head back to the API and on Design tab, in Inbound Processing box click on +Add Policy
It will show a list of policies which could be added as inbound. We would select Validate JWT:
In the following form select Full to see all the settings. The settings we are going to set for this demo are:
- Header name: Authorization
- Failed validation error message: Access token is missing or invalid.
- Require scheme: Bearer
- Output token variable name: jwt
- Issuer signing keys: a Base64 encoded string QSBzZWNyZXQgMTIzNDU2Nzg5MA==
the easy way to create Base64 is in Javascript
window.btoa('A secret 1234567890')
or in powershell
[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("A secret 1234567890"))
The JWT validate policy settings would be like:
This time, if we try our API we would get the 401 error with the message we defined:
{
"statusCode": 401,
"message": "Access token is missing or invalid."
}
Now you need to send a valid JWT token. Using the signing key which we had as 'A secret 1234567890' encode the following json
{
"sub": "1234567890",
"name": "Mohsen",
"jti": "a6bf2ab3-837f-485d-a0a4-e451b7429045",
"iat": 1582515642,
"exp": 1582519242
}
Note: You can use jsonwebtoken.io for creating JWT token.
Take the result token and go to postman and in Authorization tab select Bearer Token and paste the JWT as:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ik1vaHNlbiIsImFkbWluIjp0cnVlLCJqdGkiOiJhNmJmMmFiMy04MzdmLTQ4NWQtYTBhNC1lNDUxYjc0MjkwNDUiLCJpYXQiOjE1ODI1MTU2NDIsImV4cCI6MTU4MjUxOTM5OX0.oTcoUXkdDVUmxgy3q7XC9I2l2gZW6BYIypdKpY_XRaQ1
Now the API would return the results.
Adding claims
Head back again to the API design panel and click on the pen next to the validate-jwt in Inbound Processing. Add the following required claims and save.
With adding above required claims, the postman would return 401 again. Note the match parameter which I have used once as "All claims" for the role and once as "Any claim" for country. Add to your json a role as admin and country as "AU" or "NZ", encode it and replace the token in postman and it would work again.
{
"sub": "1234567890",
"name": "Mohsen",
"role": "admin",
"country": "AU",
"jti": "a6bf2ab3-837f-485d-a0a4-e451b7429045",
"iat": 1582515642,
"exp": 1582519242
}
If in any of the Inbound, Outbound or Backend you click on the </> icon you can see all the policies as XML: