cliffracer-auth
JWT authentication for cliffracer services, on the per-message hook chain.
Declare it like any other extension. Verification runs in worker_setup, before
the handler. A handler that reaches its body has been authenticated.
from cliffracer import CliffracerService, ServiceConfig, rpc
from cliffracer_auth import AuthConfig, AuthExtension, SimpleAuthService, get_current_user
class Orders(CliffracerService):
auth = AuthExtension(SimpleAuthService(AuthConfig(secret_key=SECRET)))
@rpc
async def create(self, item: str) -> dict[str, str]:
return {"item": item, "by": get_current_user().username}
secret_key must be at least 32 characters.
The bearer token is read from the authorization header. The header name is
compared in lower case, so a publisher may set Authorization or
authorization.
Three things are refused: a message with no token, a message with an invalid
one, and a message whose backend raised while checking. All three get
refused: unauthenticated.
Authorization
requires_auth, requires_roles and requires_permissions read the identity
the extension established:
@rpc
@requires_roles("admin")
async def delete_everything(self) -> None: ...
A caller holding a token but lacking the role gets Required roles: ('admin',).
The identity lives in a contextvar. The extension sets it in worker_setup and
resets it in worker_teardown, and carries the reset token in that dispatch's
own ctx.data. Keeping the token per dispatch is what makes concurrent
dispatches safe: a token set in one dispatch's context and reset in another's
raises inside worker_teardown.
Refusing a message
The extension refuses by raising RejectMessage. That is core's rejection
channel, and the one hook exception that stops the handler running. Core
swallows every other hook exception so that a faulty extension leaves dispatch
working, which is why a refusal needs its own channel.
The container turns a refusal into the RPC error response, runs worker_result
with it, and acks the message. A refusal is policy working.
Using a different issuer
AuthExtension accepts any object with a validate_token(token) method.
SimpleAuthService is one. Swap it to verify against another issuer and the
hook chain, the refusal path and the decorators stay as they are. The parameter
is annotated SimpleAuthService; the annotation is the narrow part, and duck
typing works.
Return an AuthContext carrying a user and a future expires_at, or return
None.
The extension gates on context.is_authenticated, which is
user is not None and is_valid, and is_valid requires expires_at to be set
and in the future. An issuer must set expires_at in the future for authentication
to succeed; otherwise requests are refused as unauthenticated.
Raising from validate_token is safe. The extension turns the exception into a
refusal and logs it under the extension's name.
Installed from PyPI, versioned in lockstep with cliffracer.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cliffracer_auth-1.0.0-py3-none-any.whl.
File metadata
- Download URL: cliffracer_auth-1.0.0-py3-none-any.whl
- Upload date:
- Size: 10.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2508bb73d5da5f62736828b6be854560f0bca6710391ebbcf4a003c8804174f5
|
|
| MD5 |
00f7618018ac544fdc93d135c2c8b9d2
|
|
| BLAKE2b-256 |
870c88d9b323a19530ffe6a0cf1f91e888053d3ba9c194fc28309b24248edb3a
|