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.comschemes:- httpsbasePath: /securityDefinitions:JWTCookie:type: apiKeyin: headername: Cookiex-flat-cookiename: authtokenx-flat-jwt:key:file: pubkey.pemalg: RS256out-var: $jwtsecurity:- JWTCookie: []paths:/projects/{p}:x-flat-flow: …get:parameters:- name: pin: pathdescription: The project identifiertype: stringrequired: truepatch:parameters:- name: pin: pathdescription: The project identifiertype: stringrequired: 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.pemalg: RS256out-var: $jwtclaims: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.pemalg: RS256out-var: $jwtclaims: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.pemalg: RS256scope-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.comschemes:- httpsbasePath: /securityDefinitions:JWTCookie:type: apiKeyin: headername: Cookiex-flat-cookiename: authtokenx-flat-jwt:key:file: pubkey.pemalg: RS256claims:iss: "https://trustworthy-token-provider.com"scope-claim: sc # default: scopeout-var: $the_claimsout-header: JWTpost-check-flow: check-jwt.xmlsecurity:- JWTCookie: []paths:/projects/{p}:x-flat-flow: ...get:parameters:- name: pin: pathdescription: The project identifiertype: stringrequired: truepatch:security:- JWTCookie: [ write ]parameters:- name: pin: pathdescription: The project identifiertype: stringrequired: 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)