API Authentication

Back

Loading concept...

🔐 Flask API Authentication: Your Secret Handshake Guide

Imagine you have a super cool treehouse. You don’t want just anyone climbing up, right? You need a secret password! That’s exactly what API Authentication is—a way to make sure only the right people can use your app.


🎭 The Story: Building a Secret Club

Think of your Flask API as a Secret Club. To get in, members need:

  1. A membership card (Token)
  2. The card must be real (Validated)
  3. It must not be expired (Fresh)

Let’s learn how to create this amazing secret club system!


🎫 Token-Based Authentication

What Is It?

Imagine going to an amusement park. You pay once, get a wristband, and then show it at every ride. You don’t pay again—you just show your wristband!

Token-based authentication works the same way:

  1. You log in once (buy the ticket)
  2. You get a special code called a token (the wristband)
  3. For every request, you show your token (flash the wristband)

Why Use Tokens?

Old Way (Sessions) New Way (Tokens)
Server remembers you Token remembers you
Needs storage Stateless
Hard to scale Easy to scale

Simple Example

# When user logs in successfully
token = "abc123xyz789"

# User sends token with every request
headers = {
    "Authorization": "Bearer abc123xyz789"
}

The word “Bearer” just means “I’m carrying this token!”


🎟️ JWT Basics

What Is JWT?

JWT stands for JSON Web Token. Think of it as a very special sealed envelope.

Inside the envelope:

  • 📝 Header: Says “this is a letter” (type of token)
  • 💌 Payload: The actual message (user info)
  • 🔏 Signature: A wax seal proving it’s real

How JWT Looks

eyJhbGciOiJIUzI1NiJ9.
eyJ1c2VyIjoiam9obiJ9.
dBjftJeZ4CVP-mB92K27uhbUJU1p1

Three parts separated by dots (.):

  1. Header (encoded)
  2. Payload (encoded)
  3. Signature (secret sauce)

JWT Flow

graph TD A["User Logs In"] --> B["Server Creates JWT"] B --> C["Server Sends JWT to User"] C --> D["User Stores JWT"] D --> E["User Sends JWT with Requests"] E --> F["Server Verifies JWT"] F --> G["Access Granted!"]

🛠️ Flask-JWT-Extended

Your New Best Friend

Flask-JWT-Extended is like a helpful robot that handles all the JWT magic for you!

Installation

pip install flask-jwt-extended

Basic Setup

from flask import Flask
from flask_jwt_extended import JWTManager

app = Flask(__name__)

# Your super secret key (keep it safe!)
app.config["JWT_SECRET_KEY"] = "super-secret"

jwt = JWTManager(app)

Creating Tokens

from flask_jwt_extended import (
    create_access_token
)

@app.route("/login", methods=["POST"])
def login():
    username = request.json.get("username")
    password = request.json.get("password")

    # Check if credentials are correct
    if username == "admin" and password == "pass":
        # Create the magic token!
        token = create_access_token(
            identity=username
        )
        return {"token": token}

    return {"error": "Bad credentials"}, 401

🔄 JWT Token Management

Access vs Refresh Tokens

Think of it like this:

  • Access Token = Day pass (short-lived, 15 minutes)
  • Refresh Token = Season pass (long-lived, 30 days)

When your day pass expires, use your season pass to get a new day pass!

Setting Up Both Tokens

from flask_jwt_extended import (
    create_access_token,
    create_refresh_token,
    jwt_required,
    get_jwt_identity
)

@app.route("/login", methods=["POST"])
def login():
    username = request.json["username"]

    # Create both tokens
    access = create_access_token(
        identity=username
    )
    refresh = create_refresh_token(
        identity=username
    )

    return {
        "access_token": access,
        "refresh_token": refresh
    }

Refresh Route

@app.route("/refresh", methods=["POST"])
@jwt_required(refresh=True)
def refresh():
    # Get who the user is
    current_user = get_jwt_identity()

    # Give them a fresh access token
    new_token = create_access_token(
        identity=current_user
    )

    return {"access_token": new_token}

Token Expiry Configuration

from datetime import timedelta

app.config["JWT_ACCESS_TOKEN_EXPIRES"] = (
    timedelta(minutes=15)
)
app.config["JWT_REFRESH_TOKEN_EXPIRES"] = (
    timedelta(days=30)
)

🛡️ Protecting API Routes

The Magic Decorator

Use @jwt_required() to protect any route!

from flask_jwt_extended import jwt_required

@app.route("/secret")
@jwt_required()
def secret():
    return {"message": "Welcome to the club!"}

Getting User Info

from flask_jwt_extended import (
    jwt_required,
    get_jwt_identity
)

@app.route("/profile")
@jwt_required()
def profile():
    # Who is making this request?
    current_user = get_jwt_identity()
    return {"user": current_user}

Optional Protection

Sometimes you want to show different things to logged-in users:

@app.route("/hello")
@jwt_required(optional=True)
def hello():
    current_user = get_jwt_identity()

    if current_user:
        return {"msg": f"Hello, {current_user}!"}
    else:
        return {"msg": "Hello, stranger!"}

Fresh Tokens for Sensitive Actions

For important actions (like changing password), require a “fresh” token:

@app.route("/change-password")
@jwt_required(fresh=True)
def change_password():
    # Only works with freshly created tokens
    return {"msg": "Password changed!"}

🌐 CORS Handling

The Problem: Different Domains

Imagine your frontend lives at myapp.com and your API lives at api.myapp.com. The browser says:

“Wait! These are different addresses! I won’t let them talk without permission!”

This is called CORS (Cross-Origin Resource Sharing).

What CORS Does

graph TD A["Frontend: myapp.com"] --> B{Browser Check} B -->|Different Origin| C["CORS Required"] C --> D["Server Says OK?"] D -->|Yes| E["Request Allowed"] D -->|No| F["Request Blocked!"]

How CORS Works

  1. Browser asks: “Can I access this API?”
  2. Server replies with headers
  3. If headers say “yes,” browser allows it

Manual CORS Headers

@app.after_request
def add_cors_headers(response):
    response.headers["Access-Control-Allow-Origin"] = "*"
    response.headers["Access-Control-Allow-Headers"] = (
        "Content-Type, Authorization"
    )
    response.headers["Access-Control-Allow-Methods"] = (
        "GET, POST, PUT, DELETE"
    )
    return response

🎯 Flask-CORS Extension

The Easy Way!

Why write all that code when there’s a helper?

Installation

pip install flask-cors

Basic Usage

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)

# Allow everyone (be careful in production!)
CORS(app)

Specific Origins

# Only allow your frontend
CORS(app, origins=["https://myapp.com"])

Route-Specific CORS

from flask_cors import cross_origin

@app.route("/public-api")
@cross_origin()
def public_api():
    return {"msg": "Anyone can access!"}

@app.route("/private-api")
def private_api():
    # No CORS here
    return {"msg": "Only same-origin!"}

Full Configuration

CORS(app,
    origins=["https://myapp.com"],
    methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["Content-Type", "Authorization"],
    supports_credentials=True
)

🚦 API Rate Limiting

Why Limit Requests?

Imagine someone keeps pressing your doorbell 1000 times per second. Annoying, right? And it might break the doorbell!

Rate limiting says: “Hey, slow down! Only 100 rings per minute allowed!”

Flask-Limiter to the Rescue

pip install flask-limiter

Basic Setup

from flask import Flask
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

app = Flask(__name__)

limiter = Limiter(
    app=app,
    key_func=get_remote_address,
    default_limits=["200 per day", "50 per hour"]
)

Route-Specific Limits

@app.route("/api/data")
@limiter.limit("10 per minute")
def get_data():
    return {"data": "Here you go!"}

@app.route("/api/expensive")
@limiter.limit("1 per minute")
def expensive_operation():
    return {"msg": "Heavy computation done!"}

Limit Formats

Format Meaning
5 per minute 5 requests every minute
100 per hour 100 requests per hour
1000 per day 1000 requests per day
1/second 1 request per second

Exempt Certain Routes

@app.route("/health")
@limiter.exempt
def health_check():
    # No limits here
    return {"status": "healthy"}

Custom Error Message

@app.errorhandler(429)
def ratelimit_handler(e):
    return {
        "error": "Slow down! Too many requests.",
        "retry_after": e.description
    }, 429

🎬 Putting It All Together

Here’s a complete example combining everything:

from flask import Flask, request
from flask_jwt_extended import (
    JWTManager,
    create_access_token,
    jwt_required,
    get_jwt_identity
)
from flask_cors import CORS
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

app = Flask(__name__)

# Configurations
app.config["JWT_SECRET_KEY"] = "super-secret"

# Initialize extensions
jwt = JWTManager(app)
CORS(app, origins=["https://myapp.com"])
limiter = Limiter(
    app=app,
    key_func=get_remote_address,
    default_limits=["100 per hour"]
)

# Login route
@app.route("/login", methods=["POST"])
@limiter.limit("5 per minute")
def login():
    data = request.json
    if data["user"] == "admin":
        token = create_access_token(
            identity=data["user"]
        )
        return {"token": token}
    return {"error": "Invalid"}, 401

# Protected route
@app.route("/secret")
@jwt_required()
def secret():
    user = get_jwt_identity()
    return {"msg": f"Hello, {user}!"}

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

🎉 You Did It!

You now know how to:

Concept You Learned
🎫 Tokens Digital wristbands for your API
🎟️ JWT The special sealed envelope
🛠️ Flask-JWT Your helpful JWT robot
🔄 Token Management Access + Refresh tokens
🛡️ Route Protection The @jwt_required() decorator
🌐 CORS Letting different domains talk
🎯 Flask-CORS Easy CORS with one line
🚦 Rate Limiting Stopping request spam

Remember: Your API is like a secret club. With these tools, you control exactly who gets in and how often they can visit!


Now go build something amazing and keep it safe! 🚀

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.