0Pricing
FastAPI Backend Development Bootcamp · Lekcja

Przepływ haseł OAuth2 i wydawanie tokenów

Implementuj schemat OAuth2PasswordBearer, haszuj hasła za pomocą passlib i wydawaj podpisane tokeny dostępu podczas logowania.

Przepływ haseł OAuth2 i wydawanie tokenów to bezpłatna lekcja FastAPI Backend Development Bootcamp na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej FastAPI Backend Development Bootcamp, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs FastAPI Backend Development Bootcamp zawiera 4 lekcji w sumie.

Części tej lekcji nie zostały jeszcze przetłumaczone i są wyświetlane po angielsku.

The OAuth2 Password Flow in Plain English

The OAuth2 password flow (a.k.a. the Resource Owner Password Credentials grant) is the simplest way to authenticate a first-party client: the user sends their username and password directly to your API, and the API hands back a signed access token.

  • The client posts credentials once to a /token endpoint.
  • The server verifies them against the database.
  • On success it returns a short-lived JWT access token.
  • Every later request carries that token in the Authorization: Bearer <token> header.

FastAPI gives us ready-made building blocks for exactly this: OAuth2PasswordBearer and OAuth2PasswordRequestForm.

Declaring the OAuth2PasswordBearer Scheme

OAuth2PasswordBearer is a FastAPI dependency that knows how to pull a bearer token out of the Authorization header. You create one instance and point its tokenUrl at the login endpoint that issues tokens.

  • tokenUrl is a relative path — it tells the docs UI where clients should request a token.
  • Using the scheme as a dependency makes the endpoint require a token; a missing or malformed header returns 401 automatically.
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer

app = FastAPI()

# 'token' matches the path of our login route below
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


@app.get("/users/me")
async def read_me(token: str = Depends(oauth2_scheme)):
    # FastAPI extracts the raw bearer token string for us
    return {"token": token}

Hashing Passwords with passlib

You must never store raw passwords. Hash them with a strong, salted algorithm. The passlib library wraps bcrypt behind a clean CryptContext API.

  • hash() produces a salted digest you store in the database.
  • verify() compares a plaintext attempt against the stored hash in constant time.
  • bcrypt is deliberately slow, which frustrates brute-force attacks.
from passlib.context import CryptContext

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


def hash_password(plain: str) -> str:
    return pwd_context.hash(plain)


def verify_password(plain: str, hashed: str) -> bool:
    return pwd_context.verify(plain, hashed)


stored = hash_password("s3cret")
print("stored looks like:", stored[:7], "...")
print("correct ->", verify_password("s3cret", stored))
print("wrong   ->", verify_password("nope", stored))

Modeling Users and a Tiny Fake Database

Before issuing tokens we need somewhere to look users up. In production this is your real database; for learning we use an in-memory dict. Notice the stored field is hashed_password, never the plaintext.

  • A Pydantic model gives the user a typed shape.
  • A get_user() helper centralizes lookups.
from pydantic import BaseModel


class UserInDB(BaseModel):
    username: str
    hashed_password: str
    disabled: bool = False


fake_users_db = {
    "alice": UserInDB(
        username="alice",
        hashed_password="$2b$12$exampleexampleexamplehashvalue",
    )
}


def get_user(username: str):
    return fake_users_db.get(username)

Authenticating the Credentials

Authentication ties the pieces together: find the user, then verify the supplied password against the stored hash. Return the user on success, or a falsy value on failure.

  • Look the user up first; if absent, fail.
  • Then call verify_password — do not short-circuit before hashing to keep timing roughly uniform.
  • The caller decides how to respond (usually a 401).
def authenticate_user(db, username: str, password: str):
    user = db.get(username)
    if not user:
        return None
    if not verify_password(password, user.hashed_password):
        return None
    return user

What a JWT Actually Is

A JSON Web Token is three base64url segments joined by dots: header.payload.signature.

  • The header names the algorithm, e.g. HS256.
  • The payload holds claims like sub (subject) and exp (expiry).
  • The signature is an HMAC of header+payload using your secret key.

JWTs are signed, not encrypted — anyone can read the payload, but nobody can forge it without the secret. Never put passwords or sensitive data in the payload.

Encoding a Signed Access Token

We sign tokens with the python-jose library (or PyJWT). Always include an exp claim so tokens expire. Store the username in the sub claim — it identifies who the token belongs to.

  • SECRET_KEY must be long, random, and kept out of source control.
  • Set a short lifetime (e.g. 15-30 minutes) for access tokens.
from datetime import datetime, timedelta, timezone
from jose import jwt

SECRET_KEY = "replace-with-a-long-random-secret"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30


def create_access_token(data: dict) -> str:
    to_encode = data.copy()
    expire = datetime.now(timezone.utc) + timedelta(
        minutes=ACCESS_TOKEN_EXPIRE_MINUTES
    )
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)


token = create_access_token({"sub": "alice"})
print("issued token segments:", token.count(".") + 1)

The Token Response Shape

The OAuth2 spec dictates the JSON your /token endpoint returns. At minimum it must include access_token and token_type, where the type is the literal string "bearer".

  • Clients read token_type to know how to send the credential back.
  • A Pydantic Token model documents and validates the response.
from pydantic import BaseModel


class Token(BaseModel):
    access_token: str
    token_type: str


example = Token(access_token="eyJhbGci...", token_type="bearer")
print(example.model_dump())

Wiring the /token Login Endpoint

The login route depends on OAuth2PasswordRequestForm, which reads form-encoded username and password fields (not JSON) — exactly what the OAuth2 password flow requires. On success it returns the Token response.

  • Failed auth raises 401 with a WWW-Authenticate: Bearer header.
  • The sub claim carries the username forward into the token.
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm

app = FastAPI()


@app.post("/token", response_model=Token)
async def login(form: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(fake_users_db, form.username, form.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token = create_access_token({"sub": user.username})
    return Token(access_token=access_token, token_type="bearer")

Decoding the Token to Find the Current User

A protected route depends on oauth2_scheme to receive the raw token, then decodes it. If the signature is invalid or the token is expired, jwt.decode raises JWTError and we return 401.

  • Read the username from the sub claim.
  • Re-load the user from the database to confirm they still exist and are active.
from fastapi import Depends, HTTPException, status
from jose import JWTError, jwt


async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exc = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username = payload.get("sub")
        if username is None:
            raise credentials_exc
    except JWTError:
        raise credentials_exc
    user = get_user(username)
    if user is None:
        raise credentials_exc
    return user

Security Practices That Matter

The mechanics work, but production hardening makes them safe:

  • Secret key: load SECRET_KEY from an environment variable; rotate it if leaked.
  • HTTPS only: tokens in headers are plaintext on the wire — TLS is mandatory.
  • Short expiry: keep access tokens brief and pair them with longer-lived refresh tokens.
  • Pin the algorithm: pass an explicit algorithms=["HS256"] list to jwt.decode to block the alg: none attack.
  • Generic errors: say "Incorrect username or password", never reveal which one was wrong.

Quick Check: The /token Endpoint

Time to test your understanding of how the FastAPI /token login route consumes credentials.

Recap: From Password to Bearer Token

You implemented the full OAuth2 password flow in FastAPI:

  • OAuth2PasswordBearer declares the bearer scheme and extracts tokens from the Authorization header.
  • passlib + bcrypt hash and verify passwords so plaintext is never stored.
  • authenticate_user looks up the user and verifies the hash, returning 401 on failure.
  • The /token route reads form credentials via OAuth2PasswordRequestForm and issues a signed JWT with a sub claim and an exp expiry.
  • get_current_user decodes and validates the token, pinning the algorithm to block forgery.

With HTTPS, an env-loaded secret, and short token lifetimes, this is a solid, idiomatic authentication foundation.

Często zadawane pytania

Czy lekcja „Przepływ haseł OAuth2 i wydawanie tokenów” jest bezpłatna?

Tak — pełny tekst „Przepływ haseł OAuth2 i wydawanie tokenów” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu FastAPI Backend Development Bootcamp, przejdź na CoddyKit PRO. Kurs FastAPI Backend Development Bootcamp zawiera 4 lekcji w sumie.

Co nauczysz się w „Przepływ haseł OAuth2 i wydawanie tokenów”?

Implementuj schemat OAuth2PasswordBearer, haszuj hasła za pomocą passlib i wydawaj podpisane tokeny dostępu podczas logowania. Ćwiczysz FastAPI Backend Development Bootcamp z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć FastAPI Backend Development Bootcamp?

Nie wymagamy żadnego doświadczenia. FastAPI Backend Development Bootcamp w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Przepływ haseł OAuth2 i wydawanie tokenów”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji FastAPI Backend Development Bootcamp?

Tak. Każda lekcja FastAPI Backend Development Bootcamp zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Przepływ haseł OAuth2 i wydawanie tokenów
  2. Podpisywanie i weryfikowanie JWT za pomocą python-jose
  3. Tokeny odświeżania i rotacja tokenów
  4. Autoryzacja oparta na zakresach i strażnicy ról
← Powrót do FastAPI Backend Development Bootcamp