-
Notifications
You must be signed in to change notification settings - Fork 10
docs: Added docs for anonymous sessions #122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fd4a9a7
6359d5c
ba12db5
d1f9338
d368de7
e5c159e
68342e0
188d68a
57b4ae5
bffec8d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -273,3 +273,74 @@ async def verify_dpop_token(access_token, dpop_proof, http_method, http_url): | |
| "proof_claims": proof_claims | ||
| } | ||
| ``` | ||
|
|
||
| ## Anonymous Callers | ||
|
|
||
| Anonymous Sessions give a visitor an Auth0 identity before they log in. The access token issued for an anonymous session is a standard Auth0 Bearer JWT, so this SDK validates it like any other token. The one difference is the `sub` claim, which starts with `anon@`. | ||
|
|
||
| An anonymous token is verified like any other. It must be issued for this API's audience. To treat anonymous callers differently, or block them, check the `sub` claim after verifying the token. The SDK does not make that authorization decision for you. | ||
|
|
||
| ### Serve everyone, branch in the handler | ||
|
|
||
| ```python | ||
| from auth0_api_python import ApiClient, ApiClientOptions | ||
|
|
||
| async def handle_cart(headers): | ||
| api_client = ApiClient(ApiClientOptions( | ||
| domain="your-tenant.auth0.com", | ||
| audience="https://api.example.com" | ||
| )) | ||
|
|
||
| claims = await api_client.verify_request(headers=headers) | ||
| is_anonymous = claims.get("sub", "").startswith("anon@") | ||
|
|
||
| if is_anonymous: | ||
| return {"cart": load_guest_cart(claims["sub"])} | ||
| return {"cart": load_user_cart(claims["sub"])} | ||
| ``` | ||
|
|
||
| > [!NOTE] | ||
| > These snippets construct `ApiClient` inside the handler for clarity. In production, build it once at startup and reuse it, or pass a shared `cache_adapter`, so JWKS and discovery caches persist across requests. | ||
|
|
||
| ### Block anonymous callers on a specific route | ||
|
|
||
| ```python | ||
| from auth0_api_python import ApiClient, ApiClientOptions | ||
|
|
||
| async def handle_checkout(headers): | ||
| api_client = ApiClient(ApiClientOptions( | ||
| domain="your-tenant.auth0.com", | ||
| audience="https://api.example.com" | ||
| )) | ||
|
|
||
| claims = await api_client.verify_request(headers=headers) | ||
| if claims.get("sub", "").startswith("anon@"): | ||
| raise PermissionError("Anonymous callers are not allowed on this route") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For an API this case is usually a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a note: blocking an anonymous caller should return an HTTP 403 Forbidden — replace PermissionError with your framework's error type. |
||
|
|
||
| return {"order": create_order(claims["sub"])} | ||
| ``` | ||
|
|
||
| > [!NOTE] | ||
| > Blocking an anonymous caller should return an HTTP `403 Forbidden`. Replace `PermissionError` with your framework's error type. | ||
|
|
||
| ### Block anonymous callers everywhere | ||
|
|
||
| The SDK has no global "reject anonymous" switch. Centralize the check in whatever shared layer your framework uses for auth (middleware, a FastAPI dependency, a decorator). | ||
|
|
||
| ```python | ||
| from auth0_api_python import ApiClient, ApiClientOptions | ||
|
|
||
| async def require_logged_in_user(headers): | ||
| api_client = ApiClient(ApiClientOptions( | ||
| domain="your-tenant.auth0.com", | ||
| audience="https://api.example.com" | ||
| )) | ||
|
|
||
| claims = await api_client.verify_request(headers=headers) | ||
| if claims.get("sub", "").startswith("anon@"): | ||
| raise PermissionError("Anonymous callers are not allowed") | ||
| return claims | ||
| ``` | ||
|
|
||
| > [!NOTE] | ||
| > The `anon@` prefix on `sub` is the only signal that distinguishes an anonymous caller from a logged-in user. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing worth flagging for readers. Building the
ApiClientinside the handler means the discovery andJWKScaches are recreated on every request, so each call refetches them. This matches the other examples in the file so it is not a blocker, but a one line note to build the client once and reuse it (or pass a sharedcache_adapter) would help people who copy this into a hot path.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a note at the end of the section: in production, build ApiClient once at startup and reuse it, or pass a shared cache_adapter, so JWKS and discovery caches persist across requests.