This tutorial builds a simple authentication system step by step. By the end you'll understand the full OAuth2 password flow and how to protect routes with JustAPI's Depends-based auth helpers.
The Problem
You need to protect a route so only authenticated users can access it. Unauthenticated requests should get a 401 error.
Step 1: Add an Auth Dependency
from justapi import JustAPIApp, Depends
from justapi.auth import OAuth2PasswordBearer
app = JustAPIApp()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/users/me")
async def read_users_me(token: str = Depends(oauth2_scheme)):
return {"token": token}
What happens here?
OAuth2PasswordBearer(tokenUrl="token")creates a dependency that expects anAuthorization: Bearer <token>header.Depends(oauth2_scheme)injects the raw token string into thetokenparameter.- If the request has no
Authorizationheader, JustAPI returns a401automatically — no code needed.
Try it
Start the server and call /users/me without a header:
{
"detail": "Not authenticated"
}
Step 2: Validate the Token
The token is just a string. We need to verify it:
from justapi import JustAPIApp, Depends, HTTPException
from justapi.auth import OAuth2PasswordBearer
app = JustAPIApp()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
fake_users_db = {
"alice": {"user_id": 1, "name": "Alice"},
"bob": {"user_id": 2, "name": "Bob"},
}
def get_current_user(token: str = Depends(oauth2_scheme)):
if token not in fake_users_db:
raise HTTPException(status_code=401, detail="Invalid token")
return fake_users_db[token]
@app.get("/users/me")
def read_users_me(current_user: dict = Depends(get_current_user)):
return current_user
Now the flow is:
- Client sends
Authorization: Bearer alice oauth2_schemeextracts"alice"as the tokenget_current_userlooks up"alice"in the database- If found, returns the user dict — which becomes
current_userin the handler - If not found, raises
401
:::note
The token "alice" is the actual value after Bearer in the header. In production this would be a JWT (see JwtAuth in the Auth API).
:::
Step 3: Add a Token Endpoint
The frontend needs a way to log in and get a token. Create a /token endpoint:
from justapi import JustAPIApp, Depends, HTTPException
from justapi.auth import OAuth2PasswordBearer
from pydantic import BaseModel
app = JustAPIApp()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
class TokenRequest(BaseModel):
username: str
password: str
fake_users_db = {
"alice": {"user_id": 1, "name": "Alice", "password": "secret123"},
"bob": {"user_id": 2, "name": "Bob", "password": "pass456"},
}
def get_current_user(token: str = Depends(oauth2_scheme)):
if token not in fake_users_db:
raise HTTPException(status_code=401, detail="Invalid token")
return fake_users_db[token]
@app.post("/token")
def login(request: TokenRequest):
user = fake_users_db.get(request.username)
if not user or user["password"] != request.password:
raise HTTPException(status_code=401, detail="Wrong username or password")
return {"access_token": request.username, "token_type": "bearer"}
@app.get("/users/me")
def read_users_me(current_user: dict = Depends(get_current_user)):
return current_user
The full flow
- Client sends
POST /tokenwith{"username": "alice", "password": "secret123"} - Server returns
{"access_token": "alice", "token_type": "bearer"} - Client sends
GET /users/mewith headerAuthorization: Bearer alice - Server returns
{"user_id": 1, "name": "Alice"}
Step 4: Add User Roles
Extend the dependency to check permissions:
def get_current_user(token: str = Depends(oauth2_scheme)):
if token not in fake_users_db:
raise HTTPException(status_code=401, detail="Invalid token")
return fake_users_db[token]
def require_admin(current_user: dict = Depends(get_current_user)):
if current_user.get("role") != "admin":
raise HTTPException(status_code=403, detail="Admin access required")
return current_user
@app.get("/admin/dashboard")
def admin_dashboard(admin: dict = Depends(require_admin)):
return {"message": f"Welcome admin {admin['name']}"}
Now /admin/dashboard requires both a valid token AND admin role.
What JustAPI Does Under the Hood
When you use Depends(oauth2_scheme):
- Before the request: JustAPI resolves the dependency, which checks the
Authorizationheader - Missing header: Returns
401with{"detail": "Not authenticated"} - Invalid header format: Returns
401with details about the expected format - Valid header: Extracts the token and passes it to your dependency
- Rust-native JWT: for production,
JwtAuth(orapp.set_jwt_auth) validates tokens entirely in Rust
Recap
OAuth2PasswordBearer(tokenUrl="token")creates the auth dependency (fromjustapi.auth)Depends(...)injects the token / user into your handler- Your dependency validates the token and returns the user
- Unauthenticated requests get a
401automatically - Chain dependencies for role-based access control
- For JWT: use
JwtAuthor the Rust-nativeapp.set_jwt_auth(...)middleware
See Also
- Get Current User — extracting user from token
- Simple OAuth2 — password-based OAuth2
- OAuth2 + JWT Tokens — production JWT implementation
- Advanced Security — OAuth2 scopes, API keys
- Auth API —
JwtAuth,OAuth2PasswordBearer, form dependencies