JSON Web Token (JWT) policy

JSON Web Token (JWT) policy

·

6 min read

This Policy is used to share information between the two parties. JSON Web tokens can grant access to resources.
These tokens are signed using a key or the public/private key.
We can choose different algorithms for these.
- HS256 algorithms use shared keys.
- RS256 algorithms use public/private keys.

When to use JWT?
Secure Data exchange:
- JWT securely transfers the information.
- The receiver can verify the content and whether it is tampered with during transit.

Authorization:
- First, the user logs in and gets the JWT from the authorization server.
- this JWT is provided to access the requested resources.
- Then in the subsequent calls user uses JWT to access the resource from the resource server.

JSON Web Token Structure:
It has 3 parts.
- Header
- Payload
- Signature
These 3 sections are separated by “.” operator.
Token in Base64 encoded format

JSON encoded format and the ASCII format of header and payload.

In this, we create two API proxies.
one to generate a JWT token
second to verify the JWT token.

**JWT Generation Flow:
**Client sends a request with a secret key. ex: secretkey=code4545.
The Generate JWT policy generates the token using the key shared through the request.
Using the Assign message policy create the response by adding a JWT token.

JWT Verification flow:
A client sends the request with the same secret key used to generate the JWT token and the JWT token.
Verify JWT Policy verifies that by using the same algorithm and secret key> if verification is successful it will send back a successful response by using the assign message policy.

Implementation

Create No target proxy.

next- passthrough-creat and deploy - editproxy - develop.
We need to send the JWT token to the client. The request comes from client - receives - while sending back in proxy endpoint - postflow - response - add generate JWT policy,

Generate JWT policy code should look like below. and Save

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<GenerateJWT continueOnError="false" enabled="true" name="Generate-JWT-1">
    <DisplayName>Generate JWT-1</DisplayName>
    <Algorithm>HS256</Algorithm>
    <SecretKey>
        <Value ref="private.key"/> <!-- secret key we will pass from query parameter-->
    </SecretKey>
    <Subject>subject-subject</Subject>
    <Issuer>urn://apigee-edge-JWT-policy-test</Issuer>
    <Audience>audience1,audience2</Audience>
    <ExpiresIn>8h</ExpiresIn><!-- token expires in 8 hours-->
    <!-- if we any additional cliams like users and all means we acan add it here
    <AdditionalClaims>
        <Claim name="additional-claim-name" type="string">additional-claim-value-goes-here</Claim>
    </AdditionalClaims>
    -->
    <!-- after token is generated it will get save in the variable "jwttokenvalue" -->
    <OutputVariable>jwttokenvalue</OutputVariable>
</GenerateJWT>

Next, pass the value tothe "private.key" through the query parameter. for that, we will use assign message policy.
Proxy endpoint - postflow - response - add assign message policy.

Before flow comes to Generate JWT policy it should pass through the assign message policy. So drag and drop to first. like below

The assign message policy code should look like the one below. and save it

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage continueOnError="false" enabled="true" name="Assign-Message-1">
    <DisplayName>Assign Message-1</DisplayName>
    <Properties/>
    <AssignVariable>
        <Name>private.key</Name>
        <Value/>
        <Ref>request.queryparam.key1</Ref>
    </AssignVariable>
    <!-- remove the query parameter comes from request afte assigning value to "private.key"-->
    <Remove>
        <QueryParams>
            <QueryParam name="key1"/>
        </QueryParams>
    </Remove>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <!-- we have to get the details from response. whatever comes we need to assign it to response-->
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

Till now we got the query param and assign the parameter value to "private.key" and removed the query parameter from the request.
then we will construct a JSON message containing the generated JWT token.
Proxy endpoint - postflow-response - add assign message policy (to construct a payload to send back to the client).

The assign message policy -2 code should look like the one below.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage continueOnError="false" enabled="true" name="Assign-Message-2">
    <DisplayName>Assign Message-2</DisplayName>
    <Properties/>
    <Set>
        <Headers/>
        <QueryParams/>
        <FormParams/>
        <Verb>POST</Verb>
        <Payload contentType="application/json">
            {
                "JWT_TOKEN": "{jwttokenvalue}"
            }
        </Payload>
        <Path/>
    </Set>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <!-- because in response flow we are addign thi payload-->
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

Save and deploy the proxy to see the output.

Jwt token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0LXN1YmplY3QiLCJhdWQiOlsiYXVkaWVuY2UxIiwiYXVkaWVuY2UyIl0sImlzcyI6InVybjovL2FwaWdlZS1lZGdlLUpXVC1wb2xpY3ktdGVzdCIsImV4cCI6MTcwMDQ5NDYzMywiaWF0IjoxNzAwNDY1ODMzLCJqdGkiOiIzNTE1NTVjMS00NjU3LTQwZDUtYjI3Zi1iMzJiMWEzODYwM2QifQ.NbJe4_2BBKaRklqyCJYVFwXSveO3xxdkKD26iIz5C08"

lets understand the structure of the token
jwt.io
paste token in encoded box.

It shows three-part :

Header

{
  "typ": "JWT",
  "alg": "HS256"
}
payload: compare with Generate JWT policy code. subject, audience, Issuer, Expiry,
and so on,.

{
  "sub": "subject-subject",
  "aud": [
    "audience1",
    "audience2"
  ],
  "iss": "urn://apigee-edge-JWT-policy-test",
  "exp": 1700494633,
  "iat": 1700465833,
  "jti": "351555c1-4657-40d5-b27f-b32b1a38603d"
}

Generate a signature based on the HMACSHA256 algorithm.


Second:
create no target proxy

next - passthrough- eval - create and deploy - edit proxy - develop.
proxy endpoint - preflow - request - add verify JWT policy.

Verify JWT policy code should look like below and save.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<VerifyJWT continueOnError="false" enabled="true" name="Verify-JWT-1">
    <DisplayName>Verify JWT-1</DisplayName>
    <Algorithm>HS256</Algorithm>
    <!-- same alsorithm used to generate the token-->
    <Source>jwttokenvalue</Source>
    <!-- we are getting jwttokenvalue from the header
    using private key it will validate-->
    <SecretKey>
        <Value ref="private.key"/>
        <!-- pass it from quey param-->
    </SecretKey>
    <Subject>subject-subject</Subject>
    <Issuer>urn://apigee-edge-JWT-policy-test</Issuer>
    <Audience>audience1,audience2</Audience>
</VerifyJWT>

we will use the assign message policy to get the value for secret key
proxy endpoint - preflow - request - add assign message policy-1

before the JWT policy, assign message policy should execute so drag it to first

Assign message policy- 1 code looks like below

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage continueOnError="false" enabled="true" name="Assign-Message-1">
    <DisplayName>Assign Message-1</DisplayName>
    <Properties/>

    <AssignVariable>
        <Name>private.key</Name>
        <Ref>request.queryparam.key1</Ref>
    </AssignVariable>
    <AssignVariable>
        <Name>jwttokenvalue</Name>
        <Ref>request.header.jwt</Ref>
    </AssignVariable>
    <!-- once it assigned lets remove the above key1 and jwt from request-->
    <Remove>
        <Headers>
            <Header name="jwt"/>
        </Headers>
        <QueryParams>
            <QueryParam name="key1"/>
        </QueryParams>
    </Remove>

    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>

once it is done we will send the response back to the client.
so we will add the assign message policy to construct JSON payload.
Proxy endpoint - postflow - response - add assign message policy-2.

Add the condition to the response flow of post flow in the proxy endpoint (default) code.
JWT.failed='' (failed = 'blank' means verification successful. if it is true means verification unsuccessfully)
then proxy endpoint(default) code should look like below.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Name>Assign-Message-1</Name>
            </Step>
            <Step>
                <Name>Verify-JWT-1</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>
    <Flows/>
    <PostFlow name="PostFlow">
        <Request/>
        <Response>
            <Step>
                <condition>JWT.failed=''</condition>
                <Name>Assign-Message-2</Name>
            </Step>
        </Response>
    </PostFlow>
    <HTTPProxyConnection>
        <BasePath>/verifyjwt</BasePath>
    </HTTPProxyConnection>
    <RouteRule name="noroute"/>
</ProxyEndpoint>

Add assign message-2 policy code should look like below.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage continueOnError="false" enabled="true" name="Assign-Message-2">
    <DisplayName>Assign Message-2</DisplayName>
    <Properties/>

    <Set>
        <Headers/>
        <QueryParams/>
        <FormParams/>
        <Verb>POST</Verb>
        <Payload contentType="application/json">
            {
                "status": "JWT validation successfull",
                "jwttoken": "{jwttokenvalue}"
            }
        </Payload>
        <Path/>
    </Set>

    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <!-- update the type. becouse plicy is in response flow-->
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

save and deploy.
output:
send the request with the secret key in the query param and the JWT token in the header.

output: modify the tomen and see the output.