Authentication is the process of verifying that a user is who they claim to be and
should be handled by the framework you are using. Some already have a built-in
authentication system (like Django); others, you have to provide it manually. It's not
Strawberry's responsibility to authenticate the user, but it can be used to create a
mutation that handles the authentication's process. It's also very important not to
confuse authentication with authorization: authorization determines what an
authenticated user can do or which data they can access. In Strawberry, this is managed
Let's see how to put together these concepts with an example. First, we define a
login mutation where we authenticate credentials and return
LoginError types depending on whether the user was successfully authenticated or not.
import strawberryfrom .types import Userfrom typing import Annotated, Union@strawberry.typeclass LoginSuccess:user: User@strawberry.typeclass LoginError:message: strLoginResult = Annotated[Union[LoginSuccess, LoginError], strawberry.union("LoginResult")]@strawberry.typeclass Mutation:@strawberry.fielddef login(self, username: str, password: str) -> LoginResult:# Your domain-specific authentication logic would go hereuser = ...if user is None:return LoginError(message="Something went wrong")return LoginSuccess(user=User(username=username))
Its fairly common to require user information within a resolver. We can do that in a type safe way with a custom context dataclass.
For example, in FastAPI this might look like this:
from functools import cached_propertyimport strawberryfrom fastapi import FastAPIfrom strawberry.fastapi import BaseContext, GraphQLRouterfrom strawberry.types import Info as _Infofrom strawberry.types.info import RootValueType@strawberry.typeclass User:... # This is just a stub for an actual user objectclass Context(BaseContext):@cached_propertydef user(self) -> User | None:if not self.request:return Noneauthorization = self.request.headers.get("Authorization", None)return authorization_service.authorize(authorization)Info = _Info[Context, RootValueType]@strawberry.typeclass Query:@strawberry.fielddef get_authenticated_user(self, info: Info) -> User | None:return info.context.userasync def get_context() -> Context:return Context()schema = strawberry.Schema(Query)graphql_app = GraphQLRouter(schema,context_getter=get_context,)app = FastAPI()app.include_router(graphql_app, prefix="/graphql")