Authorization API Reference¶
Authorizer, AuthContext, and TokenAuthorizer for handler access control.
Authorization primitives for Istos network handlers.
Istos handlers are invoked over a shared Zenoh fabric where, by default, any
peer can query any key expression. An :class:Authorizer is the hook that
decides whether an incoming request is allowed to reach a handler.
An authorizer receives an :class:AuthContext describing the request (the key
expression, parameters, and any attachment the caller sent) and returns:
- a truthy value to allow the request, or
- a falsy value — or raises :class:
~istos.errors.UnauthorizedError— to deny it.
The truthy value may be a bare True (a stateless "allowed"), or a
principal — any object identifying who made the request (for example a
:class:Principal). When an authorizer returns a principal, Istos stashes it on
the request context so the handler body can inject it with
Depends(current_principal) — the gate resolves identity once, and the body
reuses it. Both sync and async authorizers are supported.
AuthContext
dataclass
¶
Information about an incoming request, handed to an :class:Authorizer.
Source code in src/istos/security/authz.py
token
property
¶
The auth token from the request attachment (envelope-aware).
Accepts both a bare-token attachment and a structured
:class:~istos.context.RequestEnvelope.
JWTAuthorizer
¶
Authenticate a request from a JSON Web Token in its attachment.
Verifies the token's signature and standard claims (exp, and — when
configured — aud / iss) with PyJWT <https://pyjwt.readthedocs.io>_
(the istos[jwt] extra), then maps it to a :class:Principal: id from
the id_claim (sub by default), roles from roles_claim, and the
full decoded payload as claims.
Symmetric (HS) verification uses secret; asymmetric (RS/ES/PS) uses
public_key. The none algorithm is always rejected.
# HS256 shared secret:
Istos(authorizer=JWTAuthorizer(secret=os.environ["JWT_SECRET"]))
# RS256 with an identity provider's public key + audience:
Istos(authorizer=JWTAuthorizer(
public_key=PUBKEY_PEM, algorithms=["RS256"], audience="my-api"))
An absent, malformed, or invalid token is a denial (falsy → UnauthorizedError).
Source code in src/istos/security/authz.py
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | |
Principal
dataclass
¶
The authenticated identity behind a request.
A convenience shape for the value an authorizer may return to say "allowed,
and here is who". Istos treats any non-bool truthy return from an
authorizer as a principal, so you can return your own type instead; this class
is a default carrying an id, roles, and arbitrary claims.
Inject it into a handler body with Depends(current_principal).
Source code in src/istos/security/authz.py
TokenAuthorizer
¶
Shared-secret authorizer.
Allows a request only when its attachment carries one of the accepted
tokens. Callers supply the token via the attachment= argument of their
Zenoh get/put (see :meth:Istos.query_once).
istos = Istos(authorizer=TokenAuthorizer("s3cr3t"))
Source code in src/istos/security/authz.py
check_authorized(authorizer, ctx)
async
¶
Run authorizer against ctx, raising on denial.
A None authorizer is a no-op (allow). Supports sync and async
authorizers; a falsy return is treated as denial.
Returns the principal the authorizer resolved, or None when the
request was allowed without an identity (authorizer absent, or it returned a
bare True). Callers use this to expose the identity to the handler body.
Source code in src/istos/security/authz.py
combine_authorizers(app_authorizer, handler_authorizer)
¶
Resolve a handler's effective authorizer using layered semantics.
This mirrors mainstream frameworks (global middleware + route guard, Envoy ext_authz + RBAC): the app-wide gate is a baseline that always applies, and a per-handler authorizer adds an additional requirement on top of it.
handler_authorizer is None→ inherit the app-wide authorizer only.handler_authorizer is Public→ explicitly public; the app-wide gate is bypassed for this one handler.- otherwise → both the app-wide and the per-handler authorizer must allow the request (defense in depth).
Source code in src/istos/security/authz.py
require_roles(*roles, mode='all', authenticator=None)
¶
Authorize based on the authenticated principal's roles (RBAC).
Designed to layer on top of an authenticating authorizer: set the
authenticator app-wide (Istos(authorizer=JWTAuthorizer(...))) and guard
individual handlers with the roles they need::
@app.handle("admin/reset", authorizer=require_roles("admin"))
async def reset(): ...
mode="all" (default) requires every listed role; mode="any" requires
at least one. When no authenticator has run (no identity), the request is
401; when the identity lacks the roles, it is 403.
If there is no app-wide authenticator, pass authenticator= to run one
first::
require_roles("admin", authenticator=JWTAuthorizer(secret=...))