In this lab you will learn how to configure your API to use one variant of OAuth, in wich you send a bearer token to a service. You will verify this token in three ways:
- The token is generatied by the correct auothority.
- The token is meant for the API (uses th correct audience)
- The token contains the correct claim/role.
The Oauth-endpoint is an Azure AD endpoint belong to the course leader. This endpoint will not work beyond this course.
- Call the OAUTH endpoint to get a bearer token.
- Analyze the token.
- Create a new API
- Configure the API and protect it using policies.
- Call the API with the token to verify the setup.
Lastly you have some additional exercies.
First you need to authenticate to get a token. This token can then be used in all subsequent calls. If you are using Postman, or Thunder Client, you can use this collection.
If not, you are on your own.
- Import the collection. When you are done, you should have a new collection called APIm OAuth Demo.
- You need to update a collection variable. Find the collection variables and enter the name of your APIm instance under
YourAPImInstanceName
. Make sure it is in the current value. - The other settings are the identifier (userid) and client secret (password) for getting a token.
- When you have updated the setting, make sure to save.
- Open the
Get Token
request and click Send. - If you get back a 200 OK, you are set. Postman will update a variable to contain the token, and use it in later calls.
You need to make sure the token is correct and usable.
- Open a brower to https://jwt.ms/.
- Go back to Postman and copy the
access_token
value. Make sure you get the whole token and exclude the "-signs. - Paste the token into the upper textbox in the site. The site will decode the token for you, making it easier to read.
- The decoded token should look like this:
{
"typ": "JWT",
"alg": "RS256",
"kid": "jS1Xo1OWDj_52vbwGNgvQO2VzMc"
}.{
"aud": "cc565aa4-a1e5-4c05-b1cf-df19ca4c95be",
"iss": "https://login.microsoftonline.com/26ef3687-262a-44fa-95f4-208111b732e9/v2.0",
"iat": 1650818803,
"nbf": 1650818803,
"exp": 1650822703,
"aio": "E2ZgYNC/92TXIfdAHaXPcRdf91yZBAA=",
"azp": "a7364de7-ac75-4be9-93b3-895053c0a9e5",
"azpacr": "1",
"oid": "c64b33a3-8f65-49f6-a736-6c4a2a87f24d",
"rh": "0.AU8AhzbvJiom-kSV9CCBEbcy6aRaVszloQVMsc_fGcpMlb5PAAA.",
"roles": [
"Employees.Write",
"Employees.Read"
],
"sub": "c64b33a3-8f65-49f6-a736-6c4a2a87f24d",
"tid": "26ef3687-262a-44fa-95f4-208111b732e9",
"uti": "lcmiOtmW80GyOumGX0ueAA",
"ver": "2.0"
}.[Signature]
- Verify:
aud
equalscc565aa4-a1e5-4c05-b1cf-df19ca4c95be
iss
equalshttps://login.microsoftonline.com/26ef3687-262a-44fa-95f4-208111b732e9/v2.0
roles
containsEmployees.Read
These are the parts we will be using to authorize the call.
You will create the new API by using the built in Import OpenAPI functionality in APIm. It will create a new API with one single operation.
If you want to know more about open API you can find it here.
- In the portal, find the APIs listing in the left menu.
- Start adding a new API by clicking
+ Add API
at the top of the APIs list. - In the right pane, look for
Create from defintion
and clickOpenAPI
. - In the OpenAPI specification box, paste this URI:
https://raw.githubusercontent.com/mikaelsand/reactor-sthlm-api-pub/main/Session2/Lab3/Oauth%20Demo.openapi%2Bjson.json
- Leave the other as is and click Create. This will create a new API called
OAuth Demo
with one operation calledRead employee
.
The new API is empty. It contans definitions but it does not do anything. You will now configure the API to protect itself using OAuth and return a standard message if the authentication is successful.
- Click the GET Read Employee Operation.
- In the middle under Inbound processing find and click the
</>
symbol. This will open up the policy editor. - Replace everything in the editor with the content of this policy file.
- The end result looks like this:
<policies>
<inbound>
<base />
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Token invalid or did not contain required role" require-expiration-time="true" require-scheme="Bearer" require-signed-tokens="true" clock-skew="60" output-token-variable-name="jwt">
<openid-config url="https://login.microsoftonline.com/26ef3687-262a-44fa-95f4-208111b732e9/v2.0/.well-known/openid-configuration" />
<audiences>
<audience>cc565aa4-a1e5-4c05-b1cf-df19ca4c95be</audience>
</audiences>
<issuers>
<issuer>https://login.microsoftonline.com/26ef3687-262a-44fa-95f4-208111b732e9/v2.0</issuer>
</issuers>
<required-claims>
<claim name="roles" match="any">
<value>Employees.Read</value>
</claim>
</required-claims>
</validate-jwt>
<return-response>
<set-status code="200" reason="OK" />
<set-header name="content-type" exists-action="override">
<value>application/json</value>
</set-header>
<set-body>{"Message":"If you can read this, you have successfully authorized."}</set-body>
</return-response>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
The operation will now check the token for:
- Is it valid? The
open-id config
tag. - Is it meant for me? The
audiences
tag - Was it issued by the correct authority? The
issuer
tag. - Is the caller allowed to read employee data? The
required-claims
tag.
If anything is wrong a standard message and code 401 will be returned. If everything is ok a standard message and 200 OK is returned.
This API does not call any backend, it contructs the response itself.
Do not forget to save your policy.
If you imported the Postman collection there is a call created for you. It is called Get Employee and is located under the Get Token request.
You need to update the API-key for the request before sending the call. You can your your admin key. If you need help finding your admin-key, you can find the instructions here.
- Update the request header
Ocp-Apim-Subscription-Key
to contain your admin key. - Make sure you have a fresh token by using the
Get Token
request first. If this is successful, the token will be updated and can be used in theGet Employee
request. - Execute the
Get Employee
request. If everything is working, you should get back a 200 OK and this message.
{
"Message": "If you can read this, you have successfully authorized."
}
- Update the policy to use another claim and role. See what happens.
- Create a new POST operation and protect that using the claim
Employee.Write
. The token contains this claim so it will work. - Create a new PUT operation and protect it using the claim
Employee.Update
. The token does not contain this claim. - What could you do to improve the policy code? There is a lot of repeating code. Can some things be put into named values?