A JWT auth toolkit for Starlite
Project description
Starlite JWT
This library offers simple JWT authentication for Starlite.
Checkout the docs 📚.
Installation
pip install starlite-jwt
This library uses the excellent python-jose library, which supports multiple cryptographic backends. You can install either pyca/cryptography or pycryptodome, and it will be used as the backend automatically. Note that if you want to use a certificate based encryption scheme, you must install one of these backends - please refer to the python-jose readme for more details.
Example
import os
from typing import Any, Optional
from uuid import UUID, uuid4
from pydantic import BaseModel, EmailStr
from starlite import OpenAPIConfig, Request, Response, ASGIConnection, Starlite, get
from starlite_jwt import JWTAuth, Token
# Let's assume we have a User model that is a pydantic model.
# This though is not required - we need some sort of user class -
# but it can be any arbitrary value, e.g. an SQLAlchemy model, a representation of a MongoDB etc.
class User(BaseModel):
id: UUID
name: str
email: EmailStr
# The JWTAuth package requires a handler callable that takes a unique identifier, and returns the 'User'
# instance correlating to it.
#
# The identifier is the 'sub' key of the JWT, and it usually correlates to a user ID.
# It can be though any arbitrary value you decide upon - as long as the handler function provided
# can receive this value and return the model instance for it.
#
# Note: The callable can be either sync or async - both will work.
async def retrieve_user_handler(
unique_identifier: str, connection: ASGIConnection[Any, Any, Any]
) -> Optional[User]:
# logic here to retrieve the user instance
...
# The minimal configuration required for the library is the callable for the 'retrieve_user_handler' key, and a string
# value for the token secret.
#
# Important: secrets should never be hardcoded. Its best practice to pass the secret using ENV.
#
# Tip: It's also a good idea to use the pydantic settings management functionality
jwt_auth = JWTAuth(
retrieve_user_handler=retrieve_user_handler,
token_secret=os.environ.get("JWT_SECRET", "abcd123"),
# we are specifying which endpoints should be excluded from authentication. In this case the login endpoint
# and our openAPI docs.
exclude=["/login", "/schema"],
)
# Given an instance of 'JWTAuth' we can create a login handler function:
@get("/login")
def login_handler() -> Response[User]:
# we have a user instance - probably by retrieving it from persistence using another lib.
# what's important for our purposes is to have an identifier:
user = User(name="Moishe Zuchmir", email="zuchmir@moishe.com", id=uuid4())
response = jwt_auth.login(identifier=str(user.id), response_body=user)
# you can do whatever you want to update the response instance here
# e.g. response.set_cookie(...)
return response
# We also have some other routes, for example:
@get("/some-path")
def some_route_handler(request: Request[User, Token]) -> Any:
# request.user is set to the instance of user returned by the middleware
assert isinstance(request.user, User)
# request.auth is the instance of 'starlite_jwt.Token' created from the data encoded in the auth header
assert isinstance(request.auth, Token)
# do stuff ...
# We add the jwt security schema to the OpenAPI config.
openapi_config = OpenAPIConfig(
title="My API",
version="1.0.0",
components=[jwt_auth.openapi_components],
security=[jwt_auth.security_requirement],
)
# We initialize the app instance, passing to it the 'jwt_auth.middleware' and the 'openapi_config'.
app = Starlite(
route_handlers=[login_handler, some_route_handler],
middleware=[jwt_auth.middleware],
openapi_config=openapi_config,
)
Customization
This integrates with the OpenAPI configuration of Starlite, and it uses the SecurityScheme
configuration to format the header and/or cookie value.
The default implementation follows the Bearer {encoded_token}
format, but you may optionally override this configuration by modifying the openapi_component attribute of your JWTAuth
instance.
If you wanted your authentication header to be Token {encoded_token}
, you could use the following as your security scheme configuration:
from pydantic_openapi_schema.v3_1_0 import Components, SecurityScheme
from starlite_jwt import JWTAuth
class CustomJWTAuth(JWTAuth):
@property
def openapi_components(self) -> Components:
"""Creates OpenAPI documentation for the JWT auth schema used.
Returns:
An [Components][pydantic_schema_pydantic.v3_1_0.components.Components] instance.
"""
return Components(
securitySchemes={
self.openapi_security_scheme_name: SecurityScheme(
type="http",
scheme="Token",
name=self.auth_header,
bearerFormat="JWT",
description="JWT api-key authentication and authorization.",
)
}
)
Contributing
Starlite and all its official libraries is open to contributions big and small.
You can always join our discord server or join our Matrix space to discuss contributions and project maintenance. For guidelines on how to contribute to this library, please see the contribution guide.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for starlite_jwt-1.5.0-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | cdecacec7e9545a5b349f4d68bd629209c4b1191d6777d786b0043d0a177cbaa |
|
MD5 | 9a3899bf729be31524e16075d8919da4 |
|
BLAKE2b-256 | 71622d39d1feaf54e85693e1abe8e44410643151a3429b0176b15524a7c56133 |