Skip to main content

Signing JWTs

When replaying traffic, it is important to re-sign JWTs that have expired so that the application accepts these new calls. If you are seeing 401 or 403 errors during replay, that is a strong indicator you need to re-sign your JWTs.

Before you begin

  • Find the location of the secret or certificate used to sign the JWTs in your Kubernetes cluster. The Speedscale Generator and your application must both use this secret for re-signing to work.

Identify and filter transactions that need re-signing


If you already have your traffic selected, just open the snapshot, click View Traffic, and skip to step 3.

  1. Open the traffic viewer and isolate the traffic that needs JWT resigning.

View Bearer

JWT tokens are stored in the Authorization HTTP request header. The token itself is prefixed with Bearer .

  1. Create a filter for the transactions containing JWT tokens. For this example, you would click on the magnifying glass next to the location to capture all transactions for endpoint /authtoken. There will be more than one so don't define your filter too narrowly.

New Filter

  1. Store the filter for later use by clicking the Save button in the top right of the filter pane. Give it a unique name.

Create Filter

  1. Click the Advanced tab to see the raw filter JSON. Copy it to the clipboard, we will be pasting it in a couple steps.

Create a traffic transform rule

  1. Create a new Traffic Transform
  2. Edit the JSON and change the id string to a unique name that you will remember (no spaces)
  3. Paste your traffic filter into your new transform and modify it to fit in the "generator->filters->filters" section as shown below
  4. Replace /home/speedscale/secret/secret-name/key with the name of the secret from your kubernetes cluster and the key you want to use within that secret. As a reminder, secrets are stored in Kubernetes as key/value pairs so you must specify both the secret name and the key.

As an example, let's assume we have a secret like the one below:

$ kubectl get secret secret-name -o yaml

apiVersion: v1
key: S3ViZXJuZXRlc1JvY2tzIQ==
kind: Secret
annotations: |
creationTimestamp: "2022-07-28T23:33:29Z"
name: secret-name
namespace: default
resourceVersion: "470465"
uid: f4924324-88ea-43b3-9f17-18bb63a5e4c9
type: Opaque

That would yield a transform configuration like the below:

"id": "standard_jwt",
"generator": [
"filters": {
"filters": [
"include": true,
"detectedLocation": "/authtoken"
"extractor": {
"type": "http_req_header",
"config": {
"name": "Authorization"
"transforms": [
"type": "http_auth",
"config": {
"secret": "/home/speedscale/secret/secret-name/key"

Apply transform to your snapshot

Next time you create a snapshot, use standard_jwt as the transform configuration. This will tell the generator to utilize the secret during replay. If you already have a snapshot then copy/paste the above transform configuration into your snapshot transform configuration JSON section and reanalyze. This can be done from the Snapshot Summary page for your snapshot.

Replay with secrets mounted

If you are using the operator to manage replays you must instruct it to mount the secret used for re-signing the JWT token to the generator pod. Accomplish this by adding the annotation to your workload while initiating replay. For example, your complete replay annotations may look something like the following: "a125995c-e8d8-4c8b-ae31-b70a48e78052" "standard" "inventory" "true" "secret-name"

If you need mulitple secrets, then seperate them with commas (no spaces). For example, the value of would change to secret-name,secret2,secret3.