Skip to main content
CoreSDK
Core Concepts

Request Context

Where CoreSDK places authenticated claims after middleware runs. FastAPI uses request.state.coresdk_user, Flask uses g.claims, Django uses request.coresdk_claims.

Request Context

After the auth and policy middleware complete, CoreSDK attaches authenticated claims to the request. Your handler reads identity, tenant, and tracing data without touching raw headers or re-parsing the JWT.

Where claims live

The location depends on the framework:

FrameworkClaims location
FastAPIrequest.state.coresdk_user
Flaskg.claims
Djangorequest.coresdk_claims

What's in the claims

FieldTypeSource
substringJWT sub claim (user ID)
emailstringJWT email claim
rolestringJWT role claim
tenant_idstringJWT tenant_id claim
claimsdictAll raw JWT claims

FastAPI: request.state.coresdk_user

from fastapi import FastAPI, Request
from coresdk import CoreSDKClient, SDKConfig
from coresdk.middleware.fastapi import CoreSDKMiddleware

_sdk = CoreSDKClient(SDKConfig.from_env())
app = FastAPI()
app.add_middleware(CoreSDKMiddleware, sdk=_sdk)

@app.get("/api/orders")
async def get_orders(request: Request):
    user = request.state.coresdk_user

    user_id   = user.sub
    email     = user.email
    tenant_id = user.tenant_id
    role      = user.role

    # Access a raw claim not promoted to a named field
    department = user.claims.get("department", "unknown")

    return await db.fetch_orders(tenant_id=tenant_id, user_id=user_id)

Flask: g.claims

from flask import Flask, g, jsonify
from coresdk import CoreSDKClient, SDKConfig
from coresdk.middleware.flask import CoreSDKFlask

_sdk = CoreSDKClient(SDKConfig.from_env())
app = Flask(__name__)
CoreSDKFlask(_sdk, app)

@app.route("/api/orders")
def get_orders():
    claims = g.claims

    user_id   = claims["sub"]
    email     = claims["email"]
    tenant_id = claims["tenant_id"]
    role      = claims["role"]

    # Access any raw claim
    department = claims.get("department", "unknown")

    orders = db.fetch_orders(tenant_id=tenant_id, user_id=user_id)
    return jsonify(orders)

Django: request.coresdk_claims

# settings.py
MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "coresdk.django.CoreSDKMiddleware",
    # ...
]

# views.py
from django.http import JsonResponse

def get_orders(request):
    claims = request.coresdk_claims

    user_id   = claims["sub"]
    email     = claims["email"]
    tenant_id = claims["tenant_id"]
    role      = claims["role"]

    department = claims.get("department", "unknown")

    orders = list(Order.objects.filter(tenant_id=tenant_id))
    return JsonResponse({"orders": orders})

Rust: context via Tower state

In Rust/axum, authenticated identity is injected via Tower middleware extensions:

use axum::{extract::Extension, response::Json};
use coresdk_engine::auth::AuthDecision;

async fn get_orders(Extension(decision): Extension<AuthDecision>) -> Json<serde_json::Value> {
    let user_id   = &decision.claims["sub"];
    let tenant_id = &decision.claims["tenant_id"];
    let role      = &decision.claims["role"];

    // fetch orders ...
    Json(serde_json::json!({ "orders": [] }))
}

Propagating context across service calls

When calling a downstream service, forward the trace context and tenant identity so the downstream can correlate logs and enforce its own policies.

FastAPI

import httpx
from fastapi import Request

@app.get("/api/orders-with-inventory")
async def get_orders_with_inventory(request: Request):
    user = request.state.coresdk_user

    # Forward traceparent and CoreSDK identity headers
    headers = {
        "traceparent": request.headers.get("traceparent", ""),
        "X-CoreSDK-Tenant-Id": user.tenant_id,
        "X-CoreSDK-User-Id": user.sub,
    }

    async with httpx.AsyncClient() as client:
        inventory = await client.get(
            "https://inventory.internal/items",
            headers=headers,
        )

    return {"inventory": inventory.json()}

Flask

import requests
from flask import g, request as flask_request

@app.route("/api/orders-with-inventory")
def get_orders_with_inventory():
    claims = g.claims

    headers = {
        "traceparent": flask_request.headers.get("traceparent", ""),
        "X-CoreSDK-Tenant-Id": claims["tenant_id"],
        "X-CoreSDK-User-Id": claims["sub"],
    }

    inventory = requests.get(
        "https://inventory.internal/items",
        headers=headers,
    ).json()

    return jsonify({"inventory": inventory})

The receiving service must run CoreSDK (or an OTel-compatible collector) to extract and use these headers.

Require role helper

Use a FastAPI dependency to enforce roles directly in the route signature:

from fastapi import Depends, HTTPException, Request

def require_role(required_role: str):
    def _check(request: Request):
        user = request.state.coresdk_user
        if user.role != required_role:
            raise HTTPException(status_code=403, detail="Insufficient role")
        return user
    return _check

@app.get("/admin/users")
async def list_users(user=Depends(require_role("admin"))):
    return await db.list_users()

Next steps

On this page