from typing import Any, Sequence from .auth_access_token_types import AccessToken from .auth_jwt_sign_jwt import sign_jwt from .time_unix_to_iso import unix_to_iso def _is_whole(value: Any) -> bool: return isinstance(value, int) and not isinstance(value, bool) def issue_access_token( subject: str, name: str, email: str, token_version: int, jti: str, now: int, ttl_seconds: int, secret: Sequence[int], ) -> AccessToken: """A signed access token for a user who has just logged in, with the claims this API relies on: sub, name, email, ver (token version), jti, iat and exp. Everything that varies (the time, the random jti) is passed in.""" if not isinstance(subject, str) or len(subject) == 0: raise TypeError("subject must be a non-empty string") if not isinstance(name, str): raise TypeError("name must be a string") if not isinstance(email, str): raise TypeError("email must be a string") if not _is_whole(token_version) or token_version < 0: raise ValueError("tokenVersion must be a whole number, 0 or more") if not isinstance(jti, str) or len(jti) == 0: raise TypeError("jti must be a non-empty string") if not _is_whole(now): raise TypeError("now must be a whole number of Unix seconds") if not _is_whole(ttl_seconds) or ttl_seconds < 1: raise ValueError("ttlSeconds must be a whole number of at least 1") exp = now + ttl_seconds expires_at = unix_to_iso(exp) token = sign_jwt( {"sub": subject, "name": name, "email": email, "ver": token_version, "jti": jti, "iat": now, "exp": exp}, secret, ) return AccessToken(access_token=token, token_type="Bearer", expires_at=expires_at, expires_in=ttl_seconds)