Skip to content

API Authentication Capstone Project — Full Auth System Implementation

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about API Authentication Capstone Project. We cover key concepts, practical examples, and best practices to help you master this topic.

Build a complete API authentication system that supports multiple authentication methods including API keys, JWT bearer tokens, OAuth2 integration, and multi-factor authentication.

Project Overview

You will build a Flask-based authentication service that powers a simulated threat intelligence API for Durga Antivirus Pro. The service must support internal service accounts (API keys), user sessions (JWT), third-party integrations (OAuth2), and sensitive operations (MFA step-up).

flowchart TD
    A["API Auth System"] --> B["Service Accounts\nAPI Keys"]
    A --> C["User Sessions\nJWT Tokens"]
    A --> D["Third-Party\nOAuth2"]
    A --> E["Sensitive Ops\nMFA Step-Up"]
    B --> F["Threat Intelligence API"]
    C --> F
    D --> F
    E --> F
    style A fill:#dbeafe,stroke:#2563eb
    style F fill:#dcfce7,stroke:#16a34a

Requirements

1. API Key Authentication

Create a key management system:

  • POST /api/v1/keys — Generate a new API key with scopes
  • GET /api/v1/keys — List active keys (hash only)
  • DELETE /api/v1/keys/<id> — Revoke a key
  • POST /api/v1/keys/<id>/rotate — Rotate a key (new key, old one invalidated)

Store hashed keys with associated scopes and metadata.

2. JWT Authentication

Implement login and token management:

  • POST /api/v1/auth/login — Username/password returns access + refresh tokens
  • POST /api/v1/auth/refresh — Refresh token returns new access + refresh tokens
  • POST /api/v1/auth/logout — Invalidate refresh token
  • GET /api/v1/auth/me — Return current user from JWT claims

Use 15-minute access tokens and 7-day refresh tokens with rotation.

3. OAuth2 Client Credentials

Support machine-to-machine auth:

  • POST /api/v1/oauth/token — Client credentials grant
  • Validate client_id and client_secret
  • Return scoped access tokens

4. MFA Step-Up

Protect sensitive operations:

  • POST /api/v1/mfa/setup — Generate TOTP secret
  • POST /api/v1/mfa/verify — Verify TOTP code
  • Sensitive endpoints require tokens with mfa_verified: true claim

Starter Code

from flask import Flask, request, jsonify, g
from functools import wraps
import jwt, hashlib, secrets, datetime, pyotp

app = Flask(__name__)
SECRET = secrets.token_hex(32)

# In-memory stores (use Redis/DB in production)
api_keys = {}
refresh_tokens = {}
mfa_secrets = {}

# === MIDDLEWARE ===

def require_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        # Check API Key (X-API-Key header)
        api_key = request.headers.get("X-API-Key")
        if api_key:
            key_hash = hashlib.sha256(api_key.encode()).hexdigest()
            key_data = api_keys.get(key_hash)
            if key_data and key_data.get("active"):
                g.auth_type = "api_key"
                g.scopes = key_data["scopes"]
                return f(*args, **kwargs)

        # Check Bearer JWT
        auth = request.headers.get("Authorization", "")
        if auth.startswith("Bearer "):
            try:
                payload = jwt.decode(
                    auth[7:], SECRET, algorithms=["HS256"]
                )
                g.auth_type = "jwt"
                g.current_user = payload
                g.scopes = payload.get("scope", "").split()
                return f(*args, **kwargs)
            except jwt.InvalidTokenError:
                pass

        return jsonify({"error": "Authentication required"}), 401
    return decorated

# === API KEY ENDPOINTS ===

@app.route("/api/v1/keys", methods=["POST"])
def create_api_key():
    data = request.get_json()
    raw_key = f"sk-{secrets.token_hex(24)}"
    key_hash = hashlib.sha256(raw_key.encode()).hexdigest()
    api_keys[key_hash] = {
        "name": data.get("name", "default"),
        "scopes": data.get("scopes", ["threat:read"]),
        "active": True,
        "created": datetime.datetime.utcnow().isoformat()
    }
    return jsonify({"api_key": raw_key, "id": key_hash[:8]})

# === JWT ENDPOINTS ===

@app.route("/api/v1/auth/login", methods=["POST"])
def login():
    data = request.get_json()
    # Validate credentials (simplified)
    if data.get("password") != "correct":
        return jsonify({"error": "Invalid credentials"}), 401

    access_token = jwt.encode({
        "sub": data.get("username"),
        "scope": "threat:read threat:write",
        "exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=15)
    }, SECRET, algorithm="HS256")

    refresh = secrets.token_urlsafe(32)
    refresh_tokens[refresh] = {"user": data.get("username")}

    return jsonify({
        "access_token": access_token,
        "refresh_token": refresh,
        "expires_in": 900
    })

# === YOUR TURN: Implement remaining endpoints ===
# 1. POST /api/v1/auth/refresh
# 2. POST /api/v1/auth/logout
# 3. POST /api/v1/oauth/token
# 4. POST /api/v1/mfa/setup
# 5. POST /api/v1/mfa/verify
# 6. Protected threat intelligence endpoints

if __name__ == "__main__":
    app.run(debug=True)

What to Implement

Build these additional features:

  1. Refresh token rotation — issue new refresh token on each use, invalidate old one
  2. Scope enforcement — resource endpoints check g.scopes against required scopes
  3. MFA step-up — certain endpoints require mfa_verified claim in JWT
  4. Rate Limiting — 5 attempts per minute on login, 100 requests per minute on API keys
  5. Audit logging — log all authentication attempts (success and failure) with timestamp, IP, method

Testing Your Project

# Test API Key auth
KEY=$(curl -s -X POST -H "Content-Type: application/json" \
  -d '{"name":"test-key","scopes":["threat:read"]}' \
  http://localhost:5000/api/v1/keys | python3 -c "import sys,json;print(json.load(sys.stdin)['api_key'])")

curl -H "X-API-Key: $KEY" http://localhost:5000/api/v1/threats

# Test JWT auth
TOKEN=$(curl -s -X POST -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"correct"}' \
  http://localhost:5000/api/v1/auth/login | python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'])")

curl -H "Authorization: Bearer $TOKEN" http://localhost:5000/api/v1/threats

Common Mistakes

1. Not Validating Scopes

API keys and JWT tokens have associated scopes. Every protected endpoint must check that the scope includes the required permission.

2. Missing Input Validation

Validate all input — email format, password strength, scope names, key names. Invalid input can cause security issues.

3. Not Handling Concurrent Token Refresh

If two requests refresh simultaneously, both may get new tokens. Use token families or detect race conditions.

4. Exposing Internal Error Details

Return generic error messages to clients. Log detailed errors server-side for debugging.

5. Forgetting HTTPS

Deploy behind HTTPS. Authentication without HTTPS is not authentication — it is theater.

Evaluation Criteria

Requirement Points
API key CRUD with hashed storage 15
JWT login with access + refresh tokens 15
Refresh token rotation 15
OAuth2 Client Credentials 10
MFA setup and step-up verification 15
Scope enforcement on all endpoints 10
Proper HTTP status codes 5
Error handling and validation 5
Audit logging 5
Code quality and documentation 5

FAQ

Should I use a real database for this project?

Start with in-memory storage. If you want production-readiness, replace with Redis (tokens, rate limits) and PostgreSQL (keys, users).

How do I test OAuth2 without a real provider?

Implement a mock authorization server that accepts any client_id/client_secret and returns tokens. Your project should work with both mock and real providers.

What Python packages do I need?

Flask, PyJWT, pyotp, hashlib (stdlib), secrets (stdlib), requests (for OAuth2 calls).

How do I handle refresh token theft?

Implement refresh token rotation and detect when a revoked token is presented. Log the event and revoke all tokens for that user.

Can I deploy this project?

Yes. Add HTTPS, replace in-memory stores with a database, add rate limiting, and it is production-ready for internal use.

What's Next

Congratulations on completing the API Authentication learning path! Continue to the JWT Complete Guide for an in-depth exploration of JSON Web Tokens.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro