# Performing Additional Checks on JWT Access Tokens

Before you start, make sure that you have read the cookbook chapter [Protecting Access using JWT Tokens](/flat/develop/cookbook/x-flat-jwt.md).

Let's start with the following swagger definition:

swagger.yaml:

```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:

* [Claims](/flat/develop/cookbook/checking-jwt-tokens.md#checking-claims)
* [Scopes](/flat/develop/cookbook/checking-jwt-tokens.md#checking-scopes)
* [Post-check flow](/flat/develop/cookbook/checking-jwt-tokens.md#the-post-check-flow)

## Checking Claims

For example, you can ensure that the token was issued by a specific token provider (`iss` claim)

```yaml
…
    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)

```yaml
…
    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:

```javascript
{
  "iss": "https://trustworthy-token-provider.com",
  "aud": [ "https://my-api.com/", "https://a-different-api.org/" ],
  …
}
```

while

```javascript
{
  "iss": "https://the-reckless-token-provider.com",
  "aud": [ "https://my-api.com/", "https://a-different-api.org/" ],
  …
}
```

or

```javascript
{
  "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:

```yaml
…
    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`:

```yaml
…
    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:

```yaml
…
    x-flat-jwt:
      key:
        file: pubkey.pem
      …
      post-check-flow: check-jwt.xml
…
```

with check-jwt.xml:

```markup
<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

```javascript
{
  …
  "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:

```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:

```markup
<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](/flat/develop/reference/openapi-5/security.md) (reference)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sevenval.gitbook.io/flat/develop/cookbook/checking-jwt-tokens.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
