py2http.auth

Framework-independent credential checks, shared by the aiohttp middleware (py2http.middleware) and the Bottle plugins (py2http.bottle_plugins), so that both refuse the same tokens and keys for the same reasons.

>>> bearer_token('Bearer abc'), bearer_token('bearer abc'), bearer_token('Basic abc')
('abc', 'abc', '')
>>> key_matches('k-123', 'k-123'), key_matches('k-12', 'k-123'), key_matches(None, 'k')
(True, False, False)

Functions

bearer_token(authorization_header)

The token of an Authorization: Bearer <token> header, or ''.

decode_jwt(token, secret, *, algorithms[, ...])

The claims of token, or CredentialsRejected with a client-safe reason.

jwt_algorithms(secret, *[, verify, ...])

Validate a JWT verification setup, returning the algorithms as a list.

jwt_decode_kwargs([decode_kwargs])

Validate extra jwt.decode arguments (audience, issuer, leeway...), refusing those the verification setup owns.

key_matches(given, expected)

Whether the given credential equals expected, in constant time.

required_key(key, *[, name])

key, refused when empty: an empty key would let a request with no Authorization header through.

Classes

AuthPlugin()

What a plugin must be to guard a Flask app (see py2http.flask_plugins): a subclass with a challenge (the WWW-Authenticate value of a refusal) and an authenticate that raises CredentialsRejected to refuse a request.

Exceptions

CredentialsRejected

A request's credentials were refused.

class py2http.auth.AuthPlugin[source]

Bases: object

What a plugin must be to guard a Flask app (see py2http.flask_plugins): a subclass with a challenge (the WWW-Authenticate value of a refusal) and an authenticate that raises CredentialsRejected to refuse a request. It is a marker class rather than a duck-typed method name, so that a plugin which merely has some authenticate method (returning False to refuse, say) can’t be mistaken for one and let everything through.

authenticate(authorization_header, *, method, endpoint)[source]

The claims to put on the request, or None; CredentialsRejected refuses.

exception py2http.auth.CredentialsRejected[source]

Bases: Exception

A request’s credentials were refused. The message is safe to show the client: it never contains the token, nor anything about the server’s key.

py2http.auth.bearer_token(authorization_header)[source]

The token of an Authorization: Bearer <token> header, or ''.

Return type:

str

py2http.auth.decode_jwt(token, secret, *, algorithms, verify=True, decode_kwargs=None)[source]

The claims of token, or CredentialsRejected with a client-safe reason.

With verify=False neither the signature nor the claims (exp…) are checked. decode_kwargs (audience, issuer, leeway…) go to jwt.decode.

Return type:

dict

py2http.auth.jwt_algorithms(secret, *, verify=True, algorithms=('HS256',), allow_mixed_algorithm_families=False)[source]

Validate a JWT verification setup, returning the algorithms as a list.

Raises at construction time, rather than accepting forgeries at request time, when:

  • algorithms is empty, a bare string, or names an unknown or unsigned (none) algorithm (PyJWT names are case-sensitive);

  • verify is True and secret is empty (an empty HMAC secret lets anyone sign tokens), or an HMAC algorithm is asked for with a non-str/bytes secret;

  • verify is True and HMAC and public-key algorithms are mixed with one secret (the classic algorithm-confusion setup), unless allow_mixed_algorithm_families is True.

>>> jwt_algorithms('s3cret')
['HS256']
>>> jwt_algorithms('', algorithms=['HS256'])
Traceback (most recent call last):
  ...
ValueError: secret must be a non-empty key when verify=True
Return type:

list

py2http.auth.jwt_decode_kwargs(decode_kwargs=None)[source]

Validate extra jwt.decode arguments (audience, issuer, leeway…), refusing those the verification setup owns.

>>> jwt_decode_kwargs({'audience': 'my-api'})
{'audience': 'my-api'}
>>> jwt_decode_kwargs({'options': {'verify_signature': False}})
Traceback (most recent call last):
  ...
ValueError: decode_kwargs may not set ['options']; use verify= and algorithms=
Return type:

dict

py2http.auth.key_matches(given, expected)[source]

Whether the given credential equals expected, in constant time.

Return type:

bool

py2http.auth.required_key(key, *, name='api_key')[source]

key, refused when empty: an empty key would let a request with no Authorization header through.