Integration Guide

Flask Integration

For the classic Python stack

🌶️ Flask is Battle-Tested

Flask is the OG Python web framework. Simple, flexible, and trusted by millions of apps. This guide uses decorators to protect your routes.

Complete Implementation

This example uses a decorator to protect any route with Amorce verification:

from flask import Flask, request, jsonify
from amorce import verify_request, AmorceSecurityError
from functools import wraps

app = Flask(__name__)

def amorce_protected(f):
    """Decorator to verify incoming Amorce requests."""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        try:
            # Verify the request before executing the view
            verified = verify_request(
                headers=request.headers,
                body=request.get_data()
            )
            
            # Add verified agent info to Flask's g object
            from flask import g
            g.amorce_agent = verified
            
        except AmorceSecurityError as e:
            return jsonify({"error": "Unauthorized", "detail": str(e)}), 401
        
        return f(*args, **kwargs)
    
    return decorated_function

@app.route('/agent/weather', methods=['POST'])
@amorce_protected  # ← Just add this decorator
def get_weather():
    # If we get here, the request is verified
    data = request.json
    city = data.get("city", "Montreal")
    
    # Access verified agent info
    from flask import g
    agent_id = g.amorce_agent.agent_id
    print(f"✅ Verified request from: {agent_id}")
    
    return jsonify({
        "temp": 22,
        "city": city,
        "condition": "Sunny"
    })

@app.route('/agent/forecast', methods=['POST'])
@amorce_protected  # ← Reuse on any route
def get_forecast():
    data = request.json
    days = data.get("days", 7)
    
    return jsonify({
        "forecast": [
            {"day": "Mon", "temp": 20},
            {"day": "Tue", "temp": 22},
            # ...
        ][:days]
    })

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

How It Works

1. Decorator Pattern

@amorce_protected wraps your route function. It runs verification before your code executes.

2. Automatic Rejection

If verification fails, the decorator returns 401 Unauthorized immediately. Your route function never runs.

3. Verified Agent Info

Access the verified agent via g.amorce_agent anywhere in your request context.

Advanced: Intent Whitelisting

Create a stricter decorator that only allows specific intents:

def amorce_protected_strict(allowed_intents):
    """Decorator with intent whitelist."""
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            try:
                verified = verify_request(
                    headers=request.headers,
                    body=request.get_data(),
                    allowed_intents=allowed_intents  # ← Whitelist
                )
                
                from flask import g
                g.amorce_agent = verified
                
            except AmorceSecurityError as e:
                return jsonify({
                    "error": "Forbidden",
                    "detail": f"Intent not allowed: {e}"
                }), 403
            
            return f(*args, **kwargs)
        
        return decorated_function
    return decorator

@app.route('/agent/book-table', methods=['POST'])
@amorce_protected_strict(['book_table', 'check_availability'])  # ← Strict
def book_table():
    # Only these 2 intents allowed
    data = request.json
    return jsonify({"status": "confirmed", "table": "A5"})

Testing Locally

Quick way to test your Flask app with Amorce:

# Install dependencies
pip install flask amorce-sdk

# Run your app
python app.py

# In another terminal, use curl with a signed request
# (Or use the Amorce SDK from a client agent)

# Your app will verify signatures automatically!

✅ Production Ready

This code is production-ready. The decorator pattern makes it easy to protect any number of routes without duplicating verification logic.