Example Projects
End-to-end examples showing CoreSDK integration in production-style applications. Each demonstrates the OAuth app-store model: register app → get credentials → issue tokens → validate everywhere.
All examples work against a local sidecar. Set CORESDK_ENV=development for instant local testing. See Local Emulator.
FastAPI Auth Middleware
Python FastAPI service with CoreSDK middleware — every route validates Bearer tokens via gRPC and emits audit events automatically.
PythonFastAPIcoresdk
View CodeNext.js PKCE Flow
Next.js App Router app with full authorization_code + PKCE OAuth flow — users authenticate, consent to scopes, and the app holds a rotating refresh token.
Next.js 15TypeScript@cpod/sdk
View CodeGo Token Validator CLI
CLI tool that validates tokens, checks rate limits, and evaluates Rego policies — useful for debugging production auth issues without a web UI.
Gocobrasdk-go
View CodeSpring Boot Microservice
Java Spring Boot service with
@EnableCoreSDK — auto-wired token validation, scope enforcement per endpoint, and OPA policy evaluation via annotation.Java 21Spring Boot 3coresdk-spring
View Code1. FastAPI Auth Middleware (Python)
CoreSDK as a FastAPI dependency — validates every request, emits an audit event, and injects the decoded claims into the route handler.
# app/auth.py
import os
from fastapi import Depends, HTTPException, Request
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from cpod import AsyncCpodClient
from cpod.errors import AuthError, CpodError
sdk = AsyncCpodClient.from_env()
bearer = HTTPBearer()
async def require_auth(
credentials: HTTPAuthorizationCredentials = Depends(bearer),
request: Request = None,
) -> dict:
token = f"Bearer {credentials.credentials}"
try:
decision = await sdk.authorize(
token,
action=request.method.lower(),
resource=request.url.path,
)
except AuthError as e:
raise HTTPException(status_code=401, detail=str(e))
except CpodError as e:
raise HTTPException(status_code=403, detail=str(e))
# Emit audit trail
await sdk.audit.emit(
actor=decision.claims.get("sub"),
action=request.method.lower(),
resource=request.url.path,
outcome="allow",
)
return decision.claims# app/main.py
from fastapi import FastAPI, Depends
from .auth import require_auth
app = FastAPI()
@app.get("/api/orders")
async def list_orders(claims: dict = Depends(require_auth)):
return {"subject": claims["sub"], "orders": []}
@app.get("/api/reports")
async def get_reports(claims: dict = Depends(require_auth)):
# claims["scope"] contains space-separated granted scopes
if "reports.read" not in claims.get("scope", "").split():
raise HTTPException(status_code=403, detail="Missing reports.read scope")
return {"reports": []}# Start with env vars pointing at local cpod-backend
CPOD_API_URL=http://localhost:8000 \
CPOD_CLIENT_ID=app-myservice \
CPOD_CLIENT_SECRET=cs_xxxx \
fastapi dev app/main.py2. Next.js PKCE Flow (TypeScript)
Full OAuth authorization_code + PKCE flow in a Next.js App Router application. The server-side route handler holds the token; the browser never sees it.
// app/auth/callback/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { cookies } from 'next/headers'
export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url)
const code = searchParams.get('code')
const state = searchParams.get('state')
// Validate CSRF state
const cookieStore = await cookies()
const savedState = cookieStore.get('oauth_state')?.value
if (state !== savedState) {
return NextResponse.json({ error: 'state_mismatch' }, { status: 400 })
}
const codeVerifier = cookieStore.get('code_verifier')?.value!
// Exchange code for tokens (server-side — never in browser JS)
const tokenResp = await fetch(`${process.env.CPOD_API_URL}/v1/oauth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: process.env.CPOD_CLIENT_ID!,
code: code!,
redirect_uri: process.env.OAUTH_REDIRECT_URI!,
code_verifier: codeVerifier,
}),
})
const { access_token, refresh_token, expires_in } = await tokenResp.json()
const response = NextResponse.redirect(new URL('/dashboard', req.url))
// Store tokens in HttpOnly cookies — never expose to browser JS
response.cookies.set('access_token', access_token, {
httpOnly: true, secure: true, sameSite: 'lax',
maxAge: expires_in,
})
response.cookies.set('refresh_token', refresh_token, {
httpOnly: true, secure: true, sameSite: 'lax',
maxAge: 60 * 60 * 24 * 30, // 30 days
})
return response
}// app/auth/login/route.ts — initiate PKCE flow
import { NextResponse } from 'next/server'
import { cookies } from 'next/headers'
import crypto from 'crypto'
function generatePKCE() {
const verifier = crypto.randomBytes(32).toString('base64url')
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url')
return { verifier, challenge }
}
export async function GET() {
const { verifier, challenge } = generatePKCE()
const state = crypto.randomBytes(16).toString('hex')
const params = new URLSearchParams({
client_id: process.env.CPOD_CLIENT_ID!,
response_type: 'code',
redirect_uri: process.env.OAUTH_REDIRECT_URI!,
scope: 'jobs.read files.read',
code_challenge: challenge,
code_challenge_method: 'S256',
state,
})
const response = NextResponse.redirect(
`${process.env.CPOD_API_URL}/oauth/authorize?${params}`
)
const cookieStore = await cookies()
response.cookies.set('code_verifier', verifier, { httpOnly: true, sameSite: 'lax', maxAge: 300 })
response.cookies.set('oauth_state', state, { httpOnly: true, sameSite: 'lax', maxAge: 300 })
return response
}3. Go Token Validator CLI
// cmd/validate.go
package cmd
import (
"context"
"encoding/json"
"fmt"
"os"
cpod "github.com/cpod-ai/cpod-sdk-go"
"github.com/spf13/cobra"
)
var validateCmd = &cobra.Command{
Use: "validate <token>",
Short: "Validate a Bearer token and print claims",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
sdk, err := cpod.FromEnv()
if err != nil {
return err
}
decision, err := sdk.Authorize(context.Background(), "Bearer "+args[0])
if err != nil {
fmt.Fprintln(os.Stderr, "denied:", err)
os.Exit(1)
}
out, _ := json.MarshalIndent(map[string]any{
"allowed": decision.Allowed,
"subject": decision.Claims["sub"],
"scope": decision.Claims["scope"],
}, "", " ")
fmt.Println(string(out))
return nil
},
}go run ./cmd validate eyJhbGci...
# {
# "allowed": true,
# "subject": "app-myservice",
# "scope": "jobs.read files.write"
# }4. Spring Boot Microservice (Java)
// CoreSDKConfig.java
@Configuration
@EnableCoreSDK
public class CoreSDKConfig {
@Bean
public CoreSDKProperties properties() {
return CoreSDKProperties.builder()
.apiUrl(System.getenv("CPOD_API_URL"))
.clientId(System.getenv("CPOD_CLIENT_ID"))
.clientSecret(System.getenv("CPOD_CLIENT_SECRET"))
.build();
}
}// OrderController.java
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired private CoreSDK sdk;
@GetMapping
public ResponseEntity<?> listOrders(
@RequestHeader("Authorization") String authHeader
) {
AuthDecision decision = sdk.authorize(authHeader, "read", "/api/orders");
if (!decision.isAllowed()) {
return ResponseEntity.status(403).body(Map.of("error", decision.getReason()));
}
return ResponseEntity.ok(Map.of(
"subject", decision.getClaims().getSub(),
"orders", List.of()
));
}
}# application.yml
cpod:
api-url: http://localhost:8000
client-id: ${CPOD_CLIENT_ID}
client-secret: ${CPOD_CLIENT_SECRET}Running Locally
All examples follow the same pattern:
# 1. Start the local stack (see Local Emulator guide for full docker-compose)
docker compose up -d
# 2. Set SDK env vars (points at cpod-backend, not the sidecar directly)
export CPOD_API_URL=http://localhost:8000
export CPOD_CLIENT_ID=app-local
export CPOD_CLIENT_SECRET=cs_xxxx
# 3. Clone + run
git clone https://github.com/cpod-ai/example-<name>
cd example-<name>
# Python: pip install -e . && fastapi dev
# TypeScript: npm install && npm run dev
# Go: go run ./cmd
# Java: ./mvnw spring-boot:run