160 lines
No EOL
6.2 KiB
Markdown
160 lines
No EOL
6.2 KiB
Markdown
# Technical Specification: OAuth2 Controllers (Phase 6.4)
|
||
|
||
## Overview
|
||
This document provides the implementation blueprint for OAuth2 controllers in the Configurable Mock API application. The implementation follows the existing Repository-Service-Controller pattern and integrates with the admin interface.
|
||
|
||
## 1. File Structure
|
||
|
||
### New Files
|
||
- `oauth2/controller.py` – OAuth2 standard endpoints (RFC 6749, 7662, 7009, OIDC)
|
||
- `oauth2/auth_code_store.py` – In‑memory storage for authorization codes
|
||
- `templates/admin/oauth_clients.html` – List OAuth clients
|
||
- `templates/admin/oauth_client_form.html` – Create/edit client form
|
||
- `templates/admin/oauth_tokens.html` – List OAuth tokens
|
||
- `templates/admin/oauth_users.html` – List OAuth users (optional)
|
||
- `templates/oauth/authorize_consent.html` – Authorization consent page
|
||
|
||
### Modified Files
|
||
- `controllers/admin_controller.py` – Add admin OAuth2 management routes under `/admin/oauth`
|
||
- `config.py` – Add OAuth2 configuration settings
|
||
- `app.py` – Include OAuth2 router
|
||
|
||
## 2. OAuth2 Standard Endpoints
|
||
|
||
### Router: `/oauth`
|
||
| Endpoint | Method | Purpose |
|
||
|----------|--------|---------|
|
||
| `/oauth/authorize` | GET | Display consent screen |
|
||
| `/oauth/authorize` | POST | Process consent |
|
||
| `/oauth/token` | POST | Issue tokens (all grant types) |
|
||
| `/oauth/userinfo` | GET | Return user claims (OpenID Connect) |
|
||
| `/oauth/introspect` | POST | Token introspection (RFC 7662) |
|
||
| `/oauth/revoke` | POST | Token revocation (RFC 7009) |
|
||
| `/.well-known/openid-configuration` | GET | OIDC discovery metadata |
|
||
|
||
### Dependencies
|
||
- Database session: `Depends(get_db)`
|
||
- Token validation: `get_current_token_payload` (for userinfo)
|
||
- Client authentication: HTTP Basic for introspection/revocation
|
||
|
||
## 3. Admin OAuth2 Management Endpoints
|
||
|
||
### Router: `/admin/oauth`
|
||
| Endpoint | Method | Purpose |
|
||
|----------|--------|---------|
|
||
| `/admin/oauth/clients` | GET | List clients (paginated) |
|
||
| `/admin/oauth/clients/new` | GET | Create client form |
|
||
| `/admin/oauth/clients` | POST | Create client |
|
||
| `/admin/oauth/clients/{client_id}/edit` | GET | Edit client form |
|
||
| `/admin/oauth/clients/{client_id}` | POST | Update client |
|
||
| `/admin/oauth/clients/{client_id}/delete` | POST | Deactivate client |
|
||
| `/admin/oauth/tokens` | GET | List tokens with filters |
|
||
| `/admin/oauth/tokens/{token_id}/revoke` | POST | Revoke token |
|
||
| `/admin/oauth/users` | GET | List users (optional) |
|
||
|
||
### Authentication
|
||
- Protected by existing `AuthMiddleware` (session‑based).
|
||
|
||
## 4. Configuration Additions (`config.py`)
|
||
|
||
```python
|
||
# Add to Settings class
|
||
oauth2_issuer: str = "http://localhost:8000"
|
||
oauth2_access_token_expire_minutes: int = 30
|
||
oauth2_refresh_token_expire_days: int = 7
|
||
oauth2_authorization_code_expire_minutes: int = 10
|
||
oauth2_supported_grant_types: List[str] = [
|
||
"authorization_code",
|
||
"client_credentials",
|
||
"refresh_token",
|
||
]
|
||
oauth2_supported_scopes: List[str] = [
|
||
"openid", "profile", "email", "api:read", "api:write"
|
||
]
|
||
```
|
||
|
||
## 5. Authorization Code Store
|
||
|
||
Create `oauth2/auth_code_store.py` with an in‑memory dictionary protected by `asyncio.Lock`. Store authorization codes with expiration (datetime). Provide methods:
|
||
|
||
- `store_code(code: str, data: dict)`
|
||
- `get_code(code: str) -> Optional[dict]`
|
||
- `delete_code(code: str)`
|
||
|
||
## 6. Template Requirements
|
||
|
||
All admin templates extend `base.html` and use Bootstrap 5 styling.
|
||
|
||
- **oauth_clients.html**: Table with columns: Client ID, Name, Grant Types, Redirect URIs, Active, Actions.
|
||
- **oauth_client_form.html**: Form fields: client_id, client_secret (plaintext), name, redirect_uris (newline‑separated), grant_types (checkboxes), scopes (newline‑separated), is_active (checkbox).
|
||
- **oauth_tokens.html**: Table with columns: Access Token (truncated), Client, User, Scopes, Expires, Active, Revoke button.
|
||
- **authorize_consent.html**: Simple page showing client name, requested scopes, Allow/Deny buttons.
|
||
|
||
## 7. Integration with Existing Code
|
||
|
||
- Use existing `OAuthService`, `TokenService`, `ClientService`, `ScopeService`.
|
||
- Use `OAuthClientRepository`, `OAuthTokenRepository`, `OAuthUserRepository`.
|
||
- Update `app.py` to include OAuth2 router after admin router.
|
||
|
||
## 8. Security Considerations
|
||
|
||
- Validate redirect_uri exactly (including query parameters).
|
||
- Hash client secrets with bcrypt (already implemented).
|
||
- Implement token revocation by deletion from database.
|
||
- Use `state` parameter for CSRF protection in authorization flow.
|
||
- Log all authentication failures.
|
||
|
||
## 9. Implementation Steps for @coder
|
||
|
||
1. **Create authorization code store** (`oauth2/auth_code_store.py`).
|
||
2. **Implement OAuth2 controller** (`oauth2/controller.py`) with all endpoints.
|
||
3. **Extend admin controller** (`controllers/admin_controller.py`) with OAuth2 management routes.
|
||
4. **Create HTML templates** in `templates/admin/` and `templates/oauth/`.
|
||
5. **Update configuration** (`config.py`) with OAuth2 settings.
|
||
6. **Update app** (`app.py`) to include OAuth2 router.
|
||
7. **Test** with curl/Postman and verify admin pages.
|
||
|
||
## 10. Example Code Snippets
|
||
|
||
### OAuth2 Controller Example
|
||
```python
|
||
# oauth2/controller.py
|
||
@router.post("/token")
|
||
async def token_endpoint(
|
||
grant_type: str = Form(...),
|
||
client_id: Optional[str] = Form(None),
|
||
client_secret: Optional[str] = Form(None),
|
||
code: Optional[str] = Form(None),
|
||
redirect_uri: Optional[str] = Form(None),
|
||
refresh_token: Optional[str] = Form(None),
|
||
scope: Optional[str] = Form(None),
|
||
db: AsyncSession = Depends(get_db),
|
||
):
|
||
oauth_service = OAuthService(db)
|
||
if grant_type == "authorization_code":
|
||
# validate code, redirect_uri
|
||
pass
|
||
# ...
|
||
```
|
||
|
||
### Admin Controller Example
|
||
```python
|
||
# controllers/admin_controller.py
|
||
@router.get("/oauth/clients", response_class=HTMLResponse)
|
||
async def list_oauth_clients(
|
||
request: Request,
|
||
page: int = 1,
|
||
db: AsyncSession = Depends(get_db),
|
||
):
|
||
repo = OAuthClientRepository(db)
|
||
clients = await repo.get_all(skip=(page-1)*PAGE_SIZE, limit=PAGE_SIZE)
|
||
# render template
|
||
```
|
||
|
||
## 11. Next Steps (Phase 6.5)
|
||
- Update `PROJECT_PLAN.md` with completed items.
|
||
- Write integration tests for OAuth2 flows.
|
||
- Consider adding PKCE support (optional).
|
||
|
||
---
|
||
**Approval Required**: Please review this specification before implementation begins. Any changes should be documented in `PROJECT_PLAN.md`. |