JWT

Prev Next

JWT (JSON Web Token) is a compact, URL-safe, self-contained format for securely transmitting information between parties. A JWT includes claims, which are statements about a user or system, and is signed by the server. Clients send the JWT in the Authorization header with each API request, allowing the server to verify the token's authenticity and authorize access based on the claims embedded within it.

Configurations

JWT authentication mechanism has the following configurations:

Explicit Token

An explicit token refers to a token that includes clear, detailed information about the user or entity it represents. In the context of JWTs, it makes the token more self-contained by not relying on the server to retrieve user data based solely on the sub (subject) claim.

Configuration

Description

Token

The JSON Web Token string containing the signed claims.

Add token as part of the Query Parameter

You can include a token as a query parameter if needed. However, you must use this approach carefully and follow best practices to mitigate security risks.

Add token as part of the Header

JWT is commonly included in the Authorization header of HTTP requests in web applications and APIs to authenticate and authorize users. Sending the JWT in the header enables secure transmission of the token between the client and server.

Add token as part of the Cookie

In JWT authentication mechanisms that use cookies, the cookie key refers to the name or identifier of the cookie that stores the JWT. When the server sends a JWT to the client as a cookie, it specifies this key so that both the client and server know which cookie contains the token and can access or update it as needed.

Dynamic Token

A dynamic token in JWT authentication refers to a token that is generated or updated based on specific conditions, user actions, or contextual requirements. Dynamic tokens provide flexibility in authentication and authorization systems by allowing the token’s contents or validity to adapt to different scenarios.

Configuration

Description

Secret Key

The secret key is essential for securing tokens, including dynamic tokens. It is used to sign the token and to verify its integrity, allowing the server to ensure that the token has not been altered by unauthorized parties.

Algorithm

Select from one of the following:

  • SHA-1 — A hashing algorithm used to sign JWTs, though Traceable does not recommend it due to known security weaknesses.

  • SHA-256 — A secure hashing algorithm commonly used to sign JWTs, providing strong integrity protection for token verification.

Add Claim

In JWT, a claim is a piece of information about an entity, usually the user, encoded in the token. Claims convey details, such as the user's identity, token expiration, roles, or permissions. They appear in the token's payload and define the token's purpose and access capabilities.

Claims appear as key-value pairs inside the JWT payload, which is a JSON object. The following is an example of a JWT payload containing claims:

{
  "sub": "1234567890",
  "name": "John Doe",
  "role": "user",
  "exp": 1632086400
}

In this example:

  • The sub claim identifies the subject (user) as 1234567890.

  • The name claim provides the user's name as John Doe.

  • The role claim specifies that the above name has the role of user.

  • The exp claim indicates that the token is valid until the timestamp 1632086400.


Example

The following are some samples that you can use to configure the JWT mechanism in the Advanced mode:

Sample 1

import os

def jwt_hook(scanctx: ScanContext, pluginctx: PluginContext, testcase: TestCase, **kwargs) -> list[Assertion]:
    attributes = testcase.get_attributes()

    token = os.getenv("session_value")
    set_key = "sesison"
    # set api key in cookie
    attributes.set("mutated.http.request.cookie.%s" % set_key, token)
    return []

Sample 2

import json
import jwt
import requests
import time
import os

TEX_URL_MAP = {
    'stg': 'TOKEN_VALUE',
    'prd': 'TOKEN_VALUE'
}

SKYLINE_HOSTS_STAGING = ["TOKEN_VALUE"]
PURE1_HOSTS_STAGING = ["sTOKEN_VALUE", "TOKEN_VALUE"]

def sign_id_token():
    #iss, priv_pem = load_issuer_and_pem(iss_file, priv_pem_file)
    iss = "TOKEN_VALUE"
    priv_pem = os.environ.get("TOKEN_PRIVATE_KEY")
    # Create a JWT token using my issuer and private key
    token = jwt.encode(
        {
            'iss': iss.strip(),
            'iat': int(time.time()),
            'exp': int(time.time()) + 36000
        },
        priv_pem,
        algorithm='RS256'
    )
    return token

def exchange_token(env, id_token, audience = None):
    # Make API Call
    data = {
        "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
        "subject_token": id_token,
        "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
    }

    if audience:
        data["audience"] = audience

    # Public REST API
    response = requests.post("{}/oauth2/v1/token".format(TEX_URL_MAP[env]),
                             data=data,
                             verify=False)

    #print("[{}] {}".format(response.status_code, response.content))

    if response.status_code != 200:
        raise Exception("Failed to exchange token with oauth2 server /token call: {}:{}".format(response.status_code,
                                                                                                response.content))

    exchange_response = json.loads(response.content)

    #print("{}".format(exchange_response))

    return exchange_response['access_token']


def get_access_token(env, audience):
    print("Generating access token with audience : ", audience)
    # Create an internal token
    id_token = sign_id_token()

    # Exchange my id token for an access token
    access_token = exchange_token(env, id_token, audience)

    return access_token


def jwt_hook(scanctx: ScanContext, pluginctx: PluginContext, testcase: TestCase, **kwargs) -> list[Assertion]:

    #print("starting hook")

    attributes = testcase.get_attributes()
    host = attributes.get("mutated.net.host.name")
    print("mutated.net.host.name: %s" % host)
    if any(sky_host in host for sky_host in SKYLINE_HOSTS_STAGING):
        print("skyline host found")
        if scanctx.get('token.skyline.staging') != None:
            token = scanctx.get('token.skyline.staging')
        else:
            token = get_access_token('stg', 'skyline')
            scanctx.set("token.skyline.staging", token)
    elif any(pure1_host in host for pure1_host in PURE1_HOSTS_STAGING):
        if scanctx.get('token.pure1.staging') != None:
            token = scanctx.get('token.pure1.staging')
        else:
            token = get_access_token('stg', 'pure1')
            scanctx.set("token.pure1.staging", token)
    else:
        if scanctx.get('token.internal.staging') != None:
            token = scanctx.get('token.internal.staging')
        else:
            token = get_access_token('stg', None)
            scanctx.set("token.internal.staging", token)

    cookie_name = "access_token"

    jwt_value = token
    auth_attr = "mutated.http.request.cookie.%s" % cookie_name
    attributes.set("mutated.auth.attribute", "mutated.http.request.cookie.%s" % cookie_name)
    attributes.set(auth_attr, jwt_value)
    return []