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
header - with a value for the
authtoken
cookie - that is a JWT
- properly signed and
- not expired.
In addition to this, FLAT provides features for further checks:
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.
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
…
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
.
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>
- FLAT Security (reference)