Skip to content

Claims and defaults

Aliases

The ready-made annotated types for the three time-based claims:

Alias Definition
Exp Annotated[int, ExpClaim()]
Nbf Annotated[int, NbfClaim()]
Iat Annotated[int, IatClaim()]

Claim markers

Claim dataclass

Claim()

Bases: ABC

Base class for JWT claim validators.

Subclass it, set __claim_name__ and implement check(), then attach the instance to a field with Annotated. The marker runs as an "after" validator, so check() sees the value once the field's own type has been applied.

Validation can be skipped per call by passing context={'validate_claims': False} to model_validate().

Attributes:

Name Type Description
__claim_name__ str

Name of the claim, reported in the error context.

Examples:

from typing import Annotated


@dataclass(frozen=True)
class AuthTimeClaim(Claim):
    __claim_name__ = 'auth_time'

    def check(self, value: Any) -> bool:
        return value <= time.time()


auth_time: Annotated[int, AuthTimeClaim()]

check abstractmethod

check(value: Any) -> bool

Return whether the claim value is acceptable.

Return False for a well-formed value that fails the rule; raise PydanticCustomError('jwt_type', ...) for a value of the wrong shape, so callers can tell the two apart.

Source code in pydantic_jwt/claims.py
@abstractmethod
def check(self, value: Any) -> bool:
    """Return whether the claim value is acceptable.

    Return `False` for a well-formed value that fails the rule; raise
    `PydanticCustomError('jwt_type', ...)` for a value of the wrong shape,
    so callers can tell the two apart.
    """
    raise NotImplementedError

ExpClaim dataclass

ExpClaim(leeway: float = 0.0)

Bases: Claim

Reject tokens whose expiry time has passed.

Attributes:

Name Type Description
leeway float

Seconds of clock skew to tolerate past the expiry.

NbfClaim dataclass

NbfClaim(leeway: float = 0.0)

Bases: Claim

Reject tokens that are not valid yet.

Attributes:

Name Type Description
leeway float

Seconds of clock skew to tolerate before the start time.

IatClaim dataclass

IatClaim(leeway: float = 0.0)

Bases: Claim

Reject tokens issued in the future.

Attributes:

Name Type Description
leeway float

Seconds of clock skew to tolerate on the issuer's clock.

IssClaim dataclass

IssClaim(issuer: str)

Bases: Claim

Reject tokens that were not issued by the expected issuer.

The comparison is an exact string match.

Attributes:

Name Type Description
issuer str

The only accepted iss value.

AudClaim dataclass

AudClaim(audience: str)

Bases: Claim

Reject tokens that are not addressed to the expected audience.

Per RFC 7519 the claim may be a single string or a list of strings; a list is accepted when it contains the expected audience.

Attributes:

Name Type Description
audience str

The audience this application answers to.

Field defaults

after

after(
    *,
    weeks: float = 0,
    days: float = 0,
    hours: float = 0,
    minutes: float = 0,
    seconds: float = 0,
    milliseconds: float = 0,
) -> Any

Return a field default holding the current time plus the given duration.

The value is a default_factory, so it is recomputed for every instance. The result is truncated to whole seconds, as JWT NumericDate requires.

Parameters:

Name Type Description Default
weeks float

Weeks to add.

0
days float

Days to add.

0
hours float

Hours to add.

0
minutes float

Minutes to add.

0
seconds float

Seconds to add.

0
milliseconds float

Milliseconds to add.

0

Returns:

Type Description
Any

A Field() default suitable for an Exp, Nbf or Iat claim.

Source code in pydantic_jwt/claims.py
def after(
    *,
    weeks: float = 0,
    days: float = 0,
    hours: float = 0,
    minutes: float = 0,
    seconds: float = 0,
    milliseconds: float = 0,
) -> Any:
    """Return a field default holding the current time plus the given duration.

    The value is a `default_factory`, so it is recomputed for every instance.
    The result is truncated to whole seconds, as JWT `NumericDate` requires.

    Args:
        weeks: Weeks to add.
        days: Days to add.
        hours: Hours to add.
        minutes: Minutes to add.
        seconds: Seconds to add.
        milliseconds: Milliseconds to add.

    Returns:
        A `Field()` default suitable for an `Exp`, `Nbf` or `Iat` claim.
    """

    delta = timedelta(
        weeks=weeks,
        days=days,
        hours=hours,
        minutes=minutes,
        seconds=seconds,
        milliseconds=milliseconds,
    )
    total = delta.total_seconds()
    return Field(default_factory=lambda: int(time.time() + total))

at

at(moment: datetime) -> Any

Return a field default fixed to the given moment.

Parameters:

Name Type Description Default
moment datetime

The instant the claim should carry. Pass an aware datetime: a naive one is interpreted in the server's local timezone, which makes the token depend on where it was issued.

required

Returns:

Type Description
Any

A Field() default that yields the same timestamp for every instance.

Source code in pydantic_jwt/claims.py
def at(moment: datetime) -> Any:
    """Return a field default fixed to the given moment.

    Args:
        moment: The instant the claim should carry. Pass an aware `datetime`: a
            naive one is interpreted in the server's local timezone, which makes
            the token depend on where it was issued.

    Returns:
        A `Field()` default that yields the same timestamp for every instance.
    """

    return Field(default_factory=lambda: int(moment.timestamp()))

uuid

uuid(*, hex_uuid: bool = False) -> Any

Return a field default holding a fresh UUID4, as a hyphenated string or as hex.

Typically used for jti, so every issued token carries a unique id.

Parameters:

Name Type Description Default
hex_uuid bool

Emit the 32-character hex form without hyphens.

False

Returns:

Type Description
Any

A Field() default that yields a new UUID4 for every instance.

Source code in pydantic_jwt/claims.py
def uuid(*, hex_uuid: bool = False) -> Any:
    """Return a field default holding a fresh UUID4, as a hyphenated string or as hex.

    Typically used for `jti`, so every issued token carries a unique id.

    Args:
        hex_uuid: Emit the 32-character hex form without hyphens.

    Returns:
        A `Field()` default that yields a new UUID4 for every instance.
    """

    return Field(default_factory=lambda: _uuid.uuid4().hex if hex_uuid else str(_uuid.uuid4()))