FLAT
CouperSevenval TechnologiesDocker ImageGithub
master
master
  • Changelog
  • FLAT
  • Administration
    • Configuration
    • Docker
    • Logging
  • Cookbook
    • Using the Built-in Mocking
    • Performing Additional Checks on JWT Access Tokens
    • Logging Custom Fields
    • Using Environment Variables
    • Handling Errors with an Error Flow
    • File Serving
    • Forwarding a Request to an Upstream API
    • Extracting Common Initialization Flow Tasks
    • Encoding and Decoding JWT
    • Passing Header Fields to the Client
    • How can I pass an arbitrary header field to an upstream system?
    • Performing Additional Checks on JWT Access Tokens
    • Proxying requests to Upstream APIs
    • Increasing the Request Timeout
    • How can I see what the client requested?
    • Using Swagger UI for API Documentation
    • Testing API Requests
    • Testing with Backend Requests
    • Testing Templates
    • Sending POST Requests
    • Processing Upstream Responses
    • Protecting Access using JWT Tokens
  • Reference
    • Configuration
    • Debugging
    • flat CLI
    • Flow
    • Variables
    • OpenAPI / Swagger Integration
    • OpenAPI
      • CORS - Cross-Origin Resource Sharing
    • OpenAPI
      • Differences from Swagger
    • OpenAPI
      • Mocking
    • OpenAPI
      • Routing
    • OpenAPI
      • Security
    • OpenAPI
      • Upstream APIs
    • OpenAPI
      • Validation
    • Flow Actions
      • assert Action
      • auth Action
      • backend-flow Action
      • copy Action
      • debug Action
      • dump Action
      • echo Action
      • error Action
      • eval Action
      • log Action
      • nameshave Action
      • pass-body Action
      • proxy-request Action
      • regex Action
      • request Action
      • requests Action
      • serve Action
      • set-config Action
      • set-env Action
      • set-response-headers Action
      • set-status Action
      • sub-flow Action
      • template Action
      • test-request Action
      • xslt Action
    • Functions
      • apply-codecs()
      • array-reverse()
      • array()
      • base64-decode()
      • base64-encode()
      • body()
      • calc-signature()
      • capitalize-first()
      • content()
      • decrypt-xml()
      • decrypt()
      • encrypt()
      • ends-with()
      • file-exists()
      • fit-document()
      • fit-log()
      • fit-serialize()
      • get-log()
      • has-class()
      • html-parse()
      • join()
      • json-doc()
      • json-parse()
      • json-stringify()
      • json-to-csv()
      • json-to-xml()
      • jwt-decode()
      • jwt-encode()
      • ldap-lookup()
      • ldap-query()
      • lookup()
      • matches()
      • md5()
      • replace()
      • sort()
      • split()
      • tolower()
      • toupper()
      • trim()
      • unixtime()
      • urldecode(), url-decode()
      • urlencode(), url-encode()
      • uuid3() and uuid4()
      • verify-signature()
      • verify-xmldsig()
      • xml-parse()
      • xml-to-json()
    • Templating
      • {{,}}
      • Comment {{// …}}
      • Dot {{.}}
      • Conditional `{{if <condition>}} … {{elseif <condition> }} … {{else}} … {{end}}
      • loop
      • ?? Operator
      • Object XML Notation (OXN)
      • Pair Producer {{: …}}
      • Placeholder
      • Template Variables
      • with
    • Testing
  • Tutorial
Powered by GitBook
On this page
  • Checking Claims
  • Checking Scopes
  • The post-check flow
  • All files together
  • See also

Was this helpful?

  1. Cookbook

Performing Additional Checks on JWT Access Tokens

PreviousUsing the Built-in MockingNextLogging Custom Fields

Last updated 4 years ago

Was this helpful?

Before you start, make sure that you have read the cookbook chapter .

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:

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

(reference)

Protecting Access using JWT Tokens
FLAT Security
Claims
Scopes
Post-check flow