> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bastion.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Request signing with JWTs

> Enable JWT request signing on a Bastion API key: upload an ES256 public key, then sign every request with iat, req-path, req-method, and body claims.

## JWT authentication

To securely authenticate API requests, Bastion supports JWT-based request signing using ES256 public keys. This guide walks you through setting up your API key for JWT authentication and how to include signed tokens in your API requests.

### Step 1: Upload a public key

To enable JWT authentication for your API key:

1. **Generate an ES256 (P-256 curve, SHA-256) public/private key pair.**

   <CodeGroup>
     ```shell theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
       openssl ecparam -name prime256v1 -genkey -noout -out es256-private.pem
       openssl ec -in es256-private.pem -pubout -out es256-public.pem
     ```
   </CodeGroup>

2. Go to your **[Bastion Dashboard](https://dashboard.prod.bastion.com/)**, find the relevant API key, and select **Add public key.**

3. In the pop-up, paste your **ES256 public key** in PEM format and select **Add public key**.

> Important: Once a public key is associated with an API key, all requests using that key must include a valid JWT. Requests without a properly signed token will be rejected.

### Step 2: Sign requests with a JWT

Each request must include an **ES256-signed JWT** in the request headers. The token must include the following claims:

* **iat** – A Unix timestamp representing the time of the request.

  * Must be **valid within 30 seconds** of the server time.
  * Cannot be **in the future**.

* **req-path** – The **full request path** and **query parameters** (e.g. `/v2/crypto/deposits?account_id=123`).

* **req-method** – The **HTTP method** used (e.g. `POST`, `PUT`, `GET`, etc.).

* **body** – The **request body**, if applicable.

  * You may omit this claim for `GET` or `HEAD` requests.
  * Ensure the request body is **serialized in the exact order** it is transmitted, then **hashed with SHA-256 and hex-encoded.**

For a working example, see [JWT generation example](/v2/api-reference/authentication/jwt-generation-example).

#### Example claims

<CodeGroup>
  ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  {
    "iat": 1754073218,
    "req-path": "/v2/accounts",
    "req-method": "POST",
    "body": "61ba41c6ce45dc6947975d178faa7ed82354fdc98c02cedaeaff64cff51134e0"
  }
  ```
</CodeGroup>

### Step 3: Send the JWT in headers

Include the signed JWT in the `bastion-signature` header:

<CodeGroup>
  ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  bastion-signature: <your-signed-jwt>
  ```
</CodeGroup>

Here’s an example using `curl`:

<CodeGroup>
  ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  curl -X POST https://api.prod.bastion.com/v2/accounts \
    -H "Authorization: Bearer <your-api-key>" \
    -H "bastion-signature: <your-signed-jwt>" \
    -H "Content-Type: application/json" \
    -d '{
      "request_id": "2de34f56-d549-5651-af61-e2316bc3c47a",
      "identity_id": "2zwoDFH1yR9ofx1DFHqNDNL2aFS"
    }'
  ```
</CodeGroup>

💡 Replace `<your-signed-jwt>` with the actual ES256 JWT, signed using your private key.

### Conclusion

Once your API key is configured with a public key, **JWTs must be used for all future requests**. This approach enhances the security of your API interactions and ensures all requests are verifiably authentic.

If you have questions about key generation, JWT formatting, or encounter issues, feel free to contact us at [try@bastion.io](mailto:try@bastion.io). We’re here to help!


## Related topics

- [JWT generation example](/v2/api-reference/authentication/jwt-generation-example.md)
- [API authentication overview](/guides/security/api-authentication.md)
- [Product updates](/changelog.md)
- [Sandbox vs. production environments](/guides/getting-started/sandbox-vs-production-environments.md)
- [Delete Signing Key](/v2/api-reference/signing-keys/delete-signing-key.md)
