Autenticação com OAuth2 e JWT no FastAPI combina um fluxo padronizado de login com tokens assinados. O cliente envia usuário e senha uma vez, recebe um token Bearer com validade curta e apresenta esse token nas rotas protegidas. JWT não é criptografia: qualquer pessoa que obtenha o token pode ler seu payload, embora não consiga alterá-lo sem invalidar a assinatura.

Este guia complementa o tutorial de como criar uma API REST com FastAPI. Em produção, use HTTPS, persista usuários em um banco, limite tentativas de login e mantenha chaves fora do código.

Dependências e fluxo de autenticação

Instale o FastAPI com os recursos padrão, PyJWT e pwdlib:

uv add "fastapi[standard]" pyjwt "pwdlib[argon2]"

O endpoint /token recebe formulário OAuth2, verifica a senha e devolve access_token e token_type. OAuth2PasswordBearer extrai o token do cabeçalho Authorization. Uma dependência valida assinatura, expiração e usuário antes de liberar a rota.

from datetime import datetime, timedelta, timezone
import jwt
from pwdlib import PasswordHash

ALGORITHM = "HS256"
password_hash = PasswordHash.recommended()

def create_access_token(subject: str, secret: str) -> str:
    expires = datetime.now(timezone.utc) + timedelta(minutes=20)
    return jwt.encode({"sub": subject, "exp": expires}, secret, algorithm=ALGORITHM)

def verify_password(plain: str, encoded: str) -> bool:
    return password_hash.verify(plain, encoded)

Carregue secret de uma fonte segura da infraestrutura. Uma string escrita no arquivo, mesmo longa, deixa de ser secreta quando entra no Git.

Valide o token em uma dependência

from typing import Annotated
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def current_username(
    token: Annotated[str, Depends(oauth2_scheme)],
) -> str:
    credentials_error = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Credenciais inválidas",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username = payload.get("sub")
        if not isinstance(username, str):
            raise credentials_error
    except jwt.InvalidTokenError:
        raise credentials_error
    return username

Passe uma lista fixa em algorithms; não aceite o algoritmo informado pelo próprio token. Depois de obter username, consulte o usuário e confira se a conta continua ativa. O campo sub deve identificar o sujeito de forma estável e não carregar informações confidenciais.

Crie o login e proteja rotas

from typing import Annotated
from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordRequestForm

app = FastAPI()

@app.post("/token")
async def login(form: Annotated[OAuth2PasswordRequestForm, Depends()]):
    user = await find_user(form.username)
    if user is None or not verify_password(form.password, user.password_hash):
        raise HTTPException(status_code=401, detail="Credenciais inválidas")
    token = create_access_token(user.username, SECRET_KEY)
    return {"access_token": token, "token_type": "bearer"}

@app.get("/me")
async def me(username: Annotated[str, Depends(current_username)]):
    return {"username": username}

Use a mesma mensagem para usuário inexistente e senha incorreta. Isso reduz a enumeração de contas. Para permissões, adicione scopes ou uma dependência de autorização separada; autenticar responde quem é o usuário, autorizar decide o que ele pode fazer.

Checklist para produção

Defina expiração curta, rotação de chaves, relógios sincronizados e política de revogação. Tokens de acesso não são uma boa sessão eterna. Se houver refresh token, armazene-o com proteção adicional, permita revogação e detecte reutilização. Registre falhas sem gravar senha nem token completo.

Teste token expirado, assinatura inválida, usuário desativado e ausência do cabeçalho. A documentação oficial do FastAPI sobre OAuth2 e JWT, consultada em 28 de julho de 2026, mantém um exemplo atualizado com hashing e tokens Bearer.