Package: authstar
AuthstarASGI Middleware that can be configured with various authenticator functions
that are used to authenticate clients from the ASGI Scope. The authenticated
client information (client_id,scopes, etc.) is added to the ASGI Scope
and can be retrieved later in the request lifecycle in order to secure
routes, require additional authentication and/or make other decisions during
the request lifecycle.In addition to the middleware,Authstarprovides an extension that can be
used withFastAPIin order to reduce the boilerplate when securing routes
and providing an OAuth2 Token endpoint.MiddlewareThe middleware should be one of the first to run. If the application is using
some type of session middleware, theAuthstarMiddlewareshould be
configured to run just after the session middleware.Example configuring the middleware forFastAPI:importfastapifromauthstarimportAuthstarMiddleware,Client,HeaderAuth,Scopeapp=fastapi.FastAPI()asyncdefon_auth_bearer(token:str)->Client|None:...asyncdefon_auth_basic(username:str,password:str)->Client|None:...asyncdefon_auth_api_key(token:str)->Client|None:...asyncdefon_auth_scope_session(scope:Scope)->Client|None:...app.add_middleware(AuthstarMiddleware,on_auth_bearer=on_auth_bearer,on_auth_basic=on_auth_basic,on_auth_header=HeaderAuth.x_api_key(on_auth_api_key),on_auth_scope=on_auth_scope_session,)Thescope_keyparameter defines the dict key in the ASGI Scope where the
client information will be stored. The default isauthstar.client. For
example, usingscope_key="users"would match what theStarletteAuthentication Middleware uses and allow for usingrequest.userif using
that framework or a framework built onStarlette.TheAuthstarClientmodel can be subclassed to allow for additional
attributes or methods to be added. If subclassing is not desired, any object
that implements theauthstar.Clientprotocol can be used.FastAPI ExtensionTheauthstar.fastapimodule provides functionality that helps to reduce
boilerplate when securing routes.Theauthstar.fastapi.RouteSecurityclass can be configured to use the
samescope_keythat the middleware uses in order to retrieve the stored
client information. The class provides several methods that can be used to
secure routes.Route AuthorizationOnce an instance is configured with thescope_key, the methods can be used
as dependencies in order to secure routes.Here are some examples. Note that the dependencies can be added to a route,
router and/or the application:fromtypingimportAnnotated,Anyimportauthstar.fastapifromauthstarimportClientfromfastapiimportAPIRouter,Securityroute_security=authstar.fastapi.RouteSecurity()insecure_router=APIRouter()router=APIRouter(dependencies=[Security(route_security.authenticated)])@insecure_router.get("/")asyncdefhomepage():...@insecure_router.get("/healthcheck",dependencies=[Security(route_security.internal)])asyncdefhealthcheck()->dict[str,str]:"""Returns HTTP 403 unless client is making request from an internal network.This example shows how to secure a route that should be accessible byunauthenticated clients where security is associated with some otherrequest attribute (client ip in this case)."""return{"status":"ok"}@insecure_router.get("/foo",dependencies=[Security(route_security.authenticated)])asyncdeffoo()->dict[str,str]:"""Returns HTTP 403 unless client is authenticated.This example shows how to secure the route if the security is not appliedat the router level, and if the client information is not required. Ifthe client information is required, then see the example below that usesthe Annotated parameter."""return{"status":"bar"}@router.get("/me")asyncdefme(auth_client:Annotated[Client,Security(route_security.authenticated)])->dict[str,Any]:"""Returns HTTP 403 unless client is unauthenticated.Also provides the client info as a parameter. The `router` is alreadysecured and requires an authenticated client. This example shows thatthe client information can be retrieved as a parameter. Even if thisroute used the `insecure_router`, it would still be secured becauseof the Annotated parameter."""returnauth_client.model_dump()@router.get("/me2")asyncdefme2(auth_client:Annotated[Client,Security(route_security.scopes,scopes=["api-user"])])->dict[str,Any]:"""Returns HTTP 403 unless client is unauthenticated and has the given scope(s).Similar to the `authenticated` method, but also checks that the client has atleast one of the specified scope values."""returnauth_client.model_dump()OAuth2 Token EndpointTheRouteSecurityclass provides a convenience method that handles the
boilerplate required to serve an OAuth2 Token Endpoint. It supports theclient_credentialsgrant type and can handle client auth using either HTTP
Basic auth (handled by theAuthstarMiddleware) or by using theclient_idandclient_secretform fields (requires an authenticator function).If anon_auth_basicauthenticator function is not provided, only HTTP Basic
Auth will be supported by the endpoint.fromauthstarimportClientfromauthstar.fastapiimportOAuth2TokenRequest,OAuth2TokenResponse,RouteSecurityfromfastapiimportAPIRouterrouter=APIRouter()route_security=RouteSecurity()asyncdefoauth2_token_builder(oauth_req:OAuth2TokenRequest,client:Client)->OAuth2TokenResponse:# build a JWT and use it to return the responsepassasyncdefverify_auth_basic(username:str,password:str)->Client|None:passrouter.post("/oauth2/token")(route_security.oauth2_token_endpoint(token_builder=oauth2_token_builder,on_auth_basic=verify_auth_basic,))OpenAPI Available AuthorizationsTheRouteSecurityclass provides a set of methods that return dependencies
that can be used to control the list of available authorizations that will be
listed in the generatedopenapi.json.openapi_api_keyopenapi_http_basicopenapi_oauth2_client_credentialsWhen used as dependencies on a route, router and/or application, they enable
clients to authorize using the given methods at the OpenAPI endpoint client.
They are strictly no-op markers and do not perform any actual
authentication/authorization.For example, adding the dependencies to therouterbelow will enable the
OpenAPI docs endpoint client to prompt for either an API Key or client
credentials (client_id/client_secret):fromauthstar.fastapiimportRouteSecurityfromfastapiimportAPIRouterroute_security=RouteSecurity()router=APIRouter(dependencies=[route_security.openapi_api_key(),route_security.openapi_oauth2_client_credentials(),],)