Performing Additional Checks on JWT Access Tokens
Before you start, make sure that you have read the cookbook chapter Protecting Access using JWT Tokens.
Let's start with the following swagger definition:
swagger.yaml:
swagger: "2.0"
host: my-api.com
schemes:
- https
basePath: /
securityDefinitions:
JWTCookie:
type: apiKey
in: header
name: Cookie
x-flat-cookiename: authtoken
x-flat-jwt:
key:
file: pubkey.pem
alg: RS256
out-var: $jwt
security:
- JWTCookie: []
paths:
/projects/{p}:
x-flat-flow: …
get:
parameters:
- name: p
in: path
description: The project identifier
type: string
required: true
patch:
parameters:
- name: p
in: path
description: The project identifier
type: string
required: true
The API has one endpoint with a path parameter p
indicating the project identifier and two operations (GET
and PATCH
). The whole API is secured with a security scheme labelled "JWTCookie".
FLAT will make sure that every request to this endpoint
has a
Cookie
headerwith a value for the
authtoken
cookiethat is a JWT
properly signed and
not expired.
In addition to this, FLAT provides features for further checks:
Checking Claims
For example, you can ensure that the token was issued by a specific token provider (iss
claim)
…
x-flat-jwt:
key:
file: pubkey.pem
alg: RS256
out-var: $jwt
claims:
iss: "https://trustworthy-token-provider.com" # ⬅ the mandatory value for the iss claim
…
and that your API is (one of) the intended audience(s) for the token (aud
claim)
…
x-flat-jwt:
key:
file: pubkey.pem
alg: RS256
out-var: $jwt
claims:
iss: "https://trustworthy-token-provider.com"
aud: "https://my-api.com/" # ⬅ a mandatory value for the aud claim
…
A JWT with the following claims will pass the test:
{
"iss": "https://trustworthy-token-provider.com",
"aud": [ "https://my-api.com/", "https://a-different-api.org/" ],
…
}
while
{
"iss": "https://the-reckless-token-provider.com",
"aud": [ "https://my-api.com/", "https://a-different-api.org/" ],
…
}
or
{
"iss": "https://trustworthy-token-provider.com",
"aud": [ "https://a-different-api.org/" ],
…
}
will not pass.
Checking Scopes
Let's restrict the use of the PATCH
operation to specially authorized requests. We can use scopes to achieve this:
…
patch:
security:
- JWTCookie: [ write ]
parameters:
…
FLAT will now look for a scope claim (default claim name is scope
) with a value of write
. If the write
scope is present (possibly along with further scopes, like in "scope": "read write create"
), the request passes, otherwise it is rejected.
BTW, you can specify another claim name for scopes using the scope-claim
property of x-flat-jwt
:
…
x-flat-jwt:
key:
file: pubkey.pem
alg: RS256
scope-claim: sc # ⬅ look for scopes in the sc JWT claim
…
The post-check flow
Finally, we want to check that a certain non-standard JWT claim pid
matches the path param p
(the project identifier).
We use the post-check-flow feature:
…
x-flat-jwt:
key:
file: pubkey.pem
…
post-check-flow: check-jwt.xml
…
with check-jwt.xml:
<flow>
<!-- $jwt contains the JWT claims, see the out-var property or x-flat-jwt -->
<log>
{
"token_id": {{ $jwt/pid }},
"path_id": {{ $request/params/p }}
}
</log>
<error if="not($jwt/pid) or $jwt/pid != $request/params/p">
{
"status": 401,
"message": "Token is not applicable for this project."
}
</error>
</flow>
A JWT with the claim
{
…
"pid": "ABC123",
…
}
will permit access to https://my-api.com/projects/ABC123
, but not to https://my-api.com/projects/DEF456
.
All files together
swagger.yaml:
swagger: "2.0"
host: my-api.com
schemes:
- https
basePath: /
securityDefinitions:
JWTCookie:
type: apiKey
in: header
name: Cookie
x-flat-cookiename: authtoken
x-flat-jwt:
key:
file: pubkey.pem
alg: RS256
claims:
iss: "https://trustworthy-token-provider.com"
scope-claim: sc # default: scope
out-var: $the_claims
out-header: JWT
post-check-flow: check-jwt.xml
security:
- JWTCookie: []
paths:
/projects/{p}:
x-flat-flow: ...
get:
parameters:
- name: p
in: path
description: The project identifier
type: string
required: true
patch:
security:
- JWTCookie: [ write ]
parameters:
- name: p
in: path
description: The project identifier
type: string
required: true
check-jwt.xml:
<flow>
<!-- $jwt contains the JWT claims, see the out-var property -->
<log>
{
"token_id": {{ $jwt/pid }},
"path_id": {{ $request/params/p }}
}
</log>
<error if="not($jwt/pid) or $jwt/pid != $request/params/p">
{
"status": 401,
"message": "Token is not applicable for this project."
}
</error>
</flow>
See also
FLAT Security (reference)
Last updated
Was this helpful?