Skip to content

Commit e97d838

Browse files
authored
✨ Add examples for AuthX authentication (#738)
2 parents 7c1c40f + 9b30e12 commit e97d838

13 files changed

+1914
-0
lines changed

examples/README.md

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# AuthX Examples
2+
3+
Simple examples showing how to use AuthX with FastAPI for authentication and authorization.
4+
5+
## Installation
6+
7+
```bash
8+
uv sync
9+
```
10+
11+
## Available Examples
12+
13+
1. **Basic Authentication** (`basic_auth_example.py`)
14+
- JWT token authentication
15+
- Protected routes
16+
17+
2. **Refresh Tokens** (`refresh_token_example.py`)
18+
- Access and refresh token handling
19+
- Token refresh flow
20+
21+
3. **Token Blocklist** (`token_blocklist_example.py`)
22+
- Token revocation
23+
- Logout functionality
24+
25+
4. **Token Locations** (`token_locations_example.py`)
26+
- Authorization headers
27+
- Cookies
28+
- Request body
29+
- Query parameters
30+
31+
5. **Fresh Tokens** (`fresh_token_example.py`)
32+
- Fresh vs non-fresh tokens
33+
- Sensitive operations protection
34+
35+
## Running Examples
36+
37+
1. Start an example:
38+
39+
```bash
40+
python example_name.py
41+
```
42+
43+
2. Access the API docs:
44+
- Open <http://localhost:8000/docs>
45+
- Test endpoints through the interactive UI
46+
47+
## Note
48+
49+
These examples are for demonstration purposes. For production use:
50+
51+
- Use environment variables for secrets
52+
- Enable HTTPS
53+
- Implement proper database storage
54+
55+
For more details, visit [AuthX Documentation](https://authx.yezz.me/)

examples/examples/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Examples of using AuthX."""
2+
3+
__version__ = "0.1.0"

examples/examples/basic_auth.py

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
from fastapi import FastAPI, HTTPException, Request
2+
from pydantic import BaseModel
3+
4+
from authx import AuthX, AuthXConfig
5+
6+
# Create a FastAPI app
7+
app = FastAPI(title="AuthX Basic Authentication Example")
8+
9+
# Configure AuthX
10+
auth_config = AuthXConfig(
11+
JWT_ALGORITHM="HS256",
12+
JWT_SECRET_KEY="your-secret-key", # In production, use a secure key and store it in environment variables
13+
JWT_TOKEN_LOCATION=["headers"], # Accept tokens in headers
14+
JWT_HEADER_TYPE="Bearer", # Use Bearer authentication
15+
)
16+
17+
# Initialize AuthX
18+
auth = AuthX(config=auth_config)
19+
20+
# Register error handlers
21+
auth.handle_errors(app)
22+
23+
24+
# Define a user model for login
25+
class User(BaseModel):
26+
username: str
27+
password: str
28+
29+
30+
# Sample user database (in a real app, you would use a database)
31+
USERS = {
32+
"user1": {"password": "password1", "email": "user1@example.com"},
33+
"user2": {"password": "password2", "email": "user2@example.com"},
34+
}
35+
36+
37+
@app.post("/login")
38+
def login(user: User):
39+
"""Login endpoint that validates credentials and returns an access token."""
40+
# Check if user exists and password is correct
41+
if user.username in USERS and USERS[user.username]["password"] == user.password:
42+
# Create an access token with the username as the subject
43+
access_token = auth.create_access_token(user.username)
44+
return {"access_token": access_token, "token_type": "bearer"}
45+
46+
# Return error if credentials are invalid
47+
raise HTTPException(status_code=401, detail="Invalid username or password")
48+
49+
50+
@app.get("/protected")
51+
async def protected_route(request: Request):
52+
"""Protected route that requires a valid access token."""
53+
try:
54+
# Get the token from the request
55+
token = await auth.get_token_from_request(request)
56+
57+
# Verify the token
58+
payload = auth.verify_token(token)
59+
60+
# Get the username from the token subject
61+
username = payload.sub
62+
63+
# Return user information
64+
return {
65+
"message": "You have access to this protected resource",
66+
"username": username,
67+
"email": USERS.get(username, {}).get("email"),
68+
}
69+
except Exception as e:
70+
# Print the error for debugging
71+
print(f"Authentication error: {str(e)}")
72+
raise HTTPException(status_code=401, detail=str(e)) from e
73+
74+
75+
@app.get("/")
76+
def read_root():
77+
"""Public route that doesn't require authentication."""
78+
return {
79+
"message": "Welcome to AuthX Basic Authentication Example",
80+
"endpoints": {
81+
"login": "POST /login - Get an access token",
82+
"protected": "GET /protected - Access protected resource (requires token)",
83+
},
84+
}
85+
86+
87+
if __name__ == "__main__":
88+
import os
89+
90+
import uvicorn
91+
92+
port = int(os.environ.get("PORT", 8000))
93+
uvicorn.run(app, host="0.0.0.0", port=port)

examples/examples/fresh_token.py

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
from fastapi import FastAPI, HTTPException, Request
2+
from pydantic import BaseModel
3+
4+
from authx import AuthX, AuthXConfig
5+
6+
# Create a FastAPI app
7+
app = FastAPI(title="AuthX Fresh Token Example")
8+
9+
# Configure AuthX
10+
auth_config = AuthXConfig(
11+
JWT_ALGORITHM="HS256",
12+
JWT_SECRET_KEY="your-secret-key", # In production, use a secure key and store it in environment variables
13+
JWT_TOKEN_LOCATION=["headers"],
14+
JWT_HEADER_TYPE="Bearer",
15+
)
16+
17+
# Initialize AuthX
18+
auth = AuthX(config=auth_config)
19+
20+
# Register error handlers
21+
auth.handle_errors(app)
22+
23+
24+
# Define models
25+
class User(BaseModel):
26+
username: str
27+
password: str
28+
29+
30+
# Sample user database (in a real app, you would use a database)
31+
USERS = {
32+
"user1": {"password": "password1", "email": "user1@example.com"},
33+
"user2": {"password": "password2", "email": "user2@example.com"},
34+
}
35+
36+
37+
@app.post("/login")
38+
def login(user: User):
39+
"""Login endpoint that validates credentials and returns a fresh token."""
40+
# Check if user exists and password is correct
41+
if user.username in USERS and USERS[user.username]["password"] == user.password:
42+
# Create a fresh token with the username as the subject
43+
fresh_token = auth.create_access_token(user.username, fresh=True)
44+
return {"fresh_token": fresh_token, "token_type": "bearer"}
45+
46+
# Return error if credentials are invalid
47+
raise HTTPException(status_code=401, detail="Invalid username or password")
48+
49+
50+
@app.post("/refresh")
51+
async def refresh_token(request: Request):
52+
"""Refresh endpoint that creates a non-fresh token using a fresh token."""
53+
try:
54+
# Get the token from the request
55+
token = await auth.get_token_from_request(request)
56+
57+
# Verify the token
58+
payload = auth.verify_token(token)
59+
60+
# Create a non-fresh token
61+
access_token = auth.create_access_token(payload.sub, fresh=False)
62+
63+
return {"access_token": access_token, "token_type": "bearer"}
64+
except Exception as e:
65+
print(f"Refresh error: {str(e)}")
66+
raise HTTPException(status_code=401, detail=str(e)) from e
67+
68+
69+
@app.get("/protected")
70+
async def protected_route(request: Request):
71+
"""Protected route that requires a valid token (fresh or non-fresh)."""
72+
try:
73+
# Get the token from the request
74+
token = await auth.get_token_from_request(request)
75+
76+
# Verify the token
77+
payload = auth.verify_token(token)
78+
79+
# Get the username from the token subject
80+
username = payload.sub
81+
82+
# Return user information
83+
return {
84+
"message": "You have access to this protected resource",
85+
"username": username,
86+
"email": USERS.get(username, {}).get("email"),
87+
"fresh": payload.fresh,
88+
}
89+
except Exception as e:
90+
print(f"Authentication error: {str(e)}")
91+
raise HTTPException(status_code=401, detail=str(e)) from e
92+
93+
94+
@app.get("/fresh-required")
95+
async def fresh_required_route(request: Request):
96+
"""Protected route that requires a fresh token."""
97+
try:
98+
# Get the token from the request
99+
token = await auth.get_token_from_request(request)
100+
101+
# Verify the token
102+
payload = auth.verify_token(token)
103+
104+
# Check if the token is fresh
105+
if not payload.fresh:
106+
raise HTTPException(status_code=401, detail="Fresh token required")
107+
108+
# Get the username from the token subject
109+
username = payload.sub
110+
111+
# Return user information
112+
return {
113+
"message": "You have access to this fresh-required resource",
114+
"username": username,
115+
"email": USERS.get(username, {}).get("email"),
116+
}
117+
except Exception as e:
118+
print(f"Authentication error: {str(e)}")
119+
raise HTTPException(status_code=401, detail=str(e)) from e
120+
121+
122+
@app.get("/")
123+
def read_root():
124+
"""Public route that doesn't require authentication."""
125+
return {
126+
"message": "Welcome to AuthX Fresh Token Example",
127+
"endpoints": {
128+
"login": "POST /login - Get a fresh token",
129+
"refresh": "POST /refresh - Get a non-fresh token using a fresh token",
130+
"protected": "GET /protected - Access protected resource (requires any token)",
131+
"fresh-required": "GET /fresh-required - Access protected resource (requires fresh token)",
132+
},
133+
}
134+
135+
136+
if __name__ == "__main__":
137+
import os
138+
139+
import uvicorn
140+
141+
port = int(os.environ.get("PORT", 8000))
142+
uvicorn.run(app, host="0.0.0.0", port=port)

0 commit comments

Comments
 (0)