duck.http.jwt.engine

Module representing Duck’s JWT store — payload management only.

Transport extraction and client delivery live in JWTMiddleware. This store is concerned only with decoding, encoding, and mutating the JWT payload — mirroring what SessionStore does for session data.

Module Contents

Classes

JWTStore

Store for decoding, encoding, and managing a JWT payload.

API

class duck.http.jwt.engine.JWTStore(raw_token: Optional[str] = None)[source]

Store for decoding, encoding, and managing a JWT payload.

Mirrors the lazy-load pattern of SessionStore — the payload is decoded on first access and mutations are tracked via modified.

Example usage:

store = JWTStore(raw_token="eyJ...")
store.load()

user_id = store.get("user_id")
store.set("role", "distributor")

if store.needs_update():
    # Reset expiry - None will resolve expiry in settings.
    store.set_expiry(store.expiry_secs)

    # Retrieve access and refresh tokens
    access, refresh = store.encode_all()

    # Send token to client here.

    # Mark the token as synced with the client.
    store.mark_updated()

Settings keys consumed:

  • JWT_SECRET_KEY — signing secret (required).

  • JWT_ALGORITHM — defaults to "HS256".

  • JWT_ACCESS_LIFETIME — default expiry in seconds, defaults to 3600.

Initialization

Initializes the JWT store.

Parameters:

raw_token – Encoded JWT string to decode on load, or None to start with an empty payload.

__contains__(key)[source]
__delitem__(key)[source]
__getitem__(key)[source]
__iter__()[source]
__repr__()[source]
__setitem__(key, value)[source]
__slots__

(‘raw_token’, ‘payload’, ‘loaded’, ‘modified’)

clear()[source]

Clears all claims from the payload.

delete(key: str)[source]

Removes a claim from the payload.

Parameters:

key – Claim key to remove.

encode() str[source]

Encodes the current payload into a signed JWT string.

Also updates raw_token with the newly encoded value.

Returns:

The signed JWT token string.

Return type:

str

Raises:

JWTError – If exp has not been set on the payload.

encode_all() Dict[str, str][source]

Returns a dictionary containing both access and refresh token.

encode_refresh_token() str[source]

This retrieves a refresh token for this store.

static ensure_loaded(method)[source]

Decorator that auto-loads the store before the method executes.

property expiry_secs: Optional[float]

Returns the remaining seconds until the token expires.

Computed live from the exp claim rather than the originally set duration, so it reflects actual time-to-expiry at call time. Returns None if no exp claim is present, and 0.0 if already expired.

Returns:

Seconds remaining, 0.0 if expired, or None if exp is not set.

Return type:

Optional[float]

get(key: str, default=None)[source]

Returns a claim value from the payload.

Parameters:
  • key – Claim key to look up.

  • default – Returned if the key is absent.

is_expired() bool[source]

Returns whether the exp claim is in the past.

Returns:

True if expired or if no exp claim is present.

Return type:

bool

items()[source]
keys()[source]
load() dict[source]

Decodes the raw token and populates the internal payload.

If no raw token was provided, the store loads with an empty payload and is treated as an unauthenticated context — no error is raised.

Returns:

The decoded JWT payload.

Return type:

dict

Raises:
  • JWTExpired – If the token’s exp claim is in the past.

  • JWTInvalid – If the token is malformed or signature verification fails.

mark_updated()[source]

Resets the modified flag after the token has been sent to the client.

needs_update() bool[source]

Returns whether the payload has unsaved modifications.

Mirrors SessionStore.needs_update — only meaningful once loaded.

Returns:

True if the store is loaded and has been modified.

Return type:

bool

reset()[source]

This will reset the set raw token.

reset_expiry()[source]

Reset the expiry to the exact seconds last used for the JWT or the seconds set in settings or default seconds.

set(key: str, value)[source]

Sets a claim and marks the store as modified.

Parameters:
  • key – Claim key.

  • value – Value to store.

set_expiry(expiry: Optional[Union[int, float, datetime.datetime, datetime.timedelta]] = None)[source]

Sets the exp claim on the payload.

Parameters:

expiry

  • int / float — seconds from now.

  • datetime.timedelta — duration added to now.

  • datetime.datetime — absolute expiry datetime.

  • None — falls back to JWT_ACCESS_LIFETIME_AGE from settings.

Raises:

JWTError – If the expiry type is not supported.

update(data: dict)[source]

Merges a dict of claims into the payload.

Parameters:

data – Claims to merge in.

values()[source]