A production-ready Spring Boot WebFlux application for AI agents to make purchases with JWT authentication, OPA policy enforcement, and comprehensive audit logging.
✅ Production-grade JWT authentication - API key to Bearer token exchange with reactive security context
✅ OPA policy enforcement - Real-time policy evaluation with resilient error handling
✅ Structured logging - SLF4J with transaction correlation IDs for production observability
✅ Database integration - H2 for development, PostgreSQL for production with Flyway migrations
✅ Agent-centric design - Digital goods focus, spending limits, capability-based authorization
Total codebase: 3,548 lines of production-ready code
- Java 17+
- Maven 3.6+
- H2 Database (for development/testing) or PostgreSQL (for production)
- Open Policy Agent (OPA) server
Clone the repository
cd payment-agent
# Build the project
mvnw clean packageFor development and testing, the application uses H2 in-memory database by default. No additional setup required - tables are created automatically via Flyway migrations.
For production environments, use PostgreSQL:
-
Install Docker Desktop: https://www.docker.com/products/docker-desktop/
-
Run a PostgreSQL container:
docker run --name payment-agent-db -e POSTGRES_DB=payment_agent -e POSTGRES_USER=payment_user -e POSTGRES_PASSWORD=payment_pass -p 5432:5432 -d postgres:13-alpine
-
Update
src/main/resources/application.properties:spring.datasource.url=jdbc:postgresql://localhost:5432/payment_agent spring.datasource.username=payment_user spring.datasource.password=payment_pass spring.datasource.driver-class-name=org.postgresql.Driver
The application automatically creates the following tables via Flyway migrations:
audit_log- Stores transaction audit recordstoken- Stores encrypted agent credentials
This project uses Flyway for database migrations. Migration scripts are located in src/main/resources/db/migration/.
Flyway is already configured in application.properties:
spring.flyway.enabled=true
spring.flyway.locations=classpath:db/migration
spring.flyway.baseline-on-migrate=trueV1__create_tables.sql- Creates audit_log and token tables
Migrations run automatically on application startup. For manual migration:
mvnw flyway:migrate-
Start Open Policy Agent:
# Windows .\opa.exe run --server --addr 127.0.0.1:8181 # Linux/Mac opa run --server --addr 127.0.0.1:8181
-
Start the application:
./mvnw spring-boot:run
The application automatically loads policies into OPA and creates H2 tables via Flyway.
- Set up PostgreSQL database (see Database Setup section)
- Start Open Policy Agent:
opa run -s
- Start the application:
mvnw spring-boot:run
# Run packaged JAR
java -jar target/payment-agent-0.0.1-SNAPSHOT.jar
# Build and run
mvnw clean package
java -jar target/payment-agent-0.0.1-SNAPSHOT.jarKey configuration properties in application.properties:
# Database (H2 for development)
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
# Flyway
spring.flyway.enabled=true
spring.flyway.locations=classpath:db/migration
spring.flyway.baseline-on-migrate=true
# OPA Server
opa.url=http://127.0.0.1:8181
# JWT Authentication
app.jwt.secret=change-me-in-production-secret-key-32-chars
app.jwt.expiration=3600
# Strong JWT metadata
app.jwt.issuer=payment-gateway
app.jwt.audience=payment-agents
# API Key HMAC (pepper)
app.apikey.hmacSecret=change-me-very-strong-32B
app.apikey.allowLegacyHash=false
# Auth Clock Skew
app.auth.clockSkewSeconds=60
# Encryption
app.encryption.key=change-me-in-production-32-charsYou can configure the same settings via environment variables (Spring Boot relaxed binding).
$env:APP_APIKEY_HMACSECRET = "this-is-a-very-strong-32B-secret-1234"
$env:APP_JWT_SECRET = "change-me-very-strong-32B-or-base64"
$env:APP_JWT_ISSUER = "payment-gateway"
$env:APP_JWT_AUDIENCE = "payment-agents"
$env:APP_AUTH_CLOCKSKEWSECONDS = "60"
export APP_APIKEY_HMACSECRET="this-is-a-very-strong-32B-secret-1234"
export APP_JWT_SECRET="change-me-very-strong-32B-or-base64"
export APP_JWT_ISSUER="payment-gateway"
export APP_JWT_AUDIENCE="payment-agents"
export APP_AUTH_CLOCKSKEWSECONDS=60
For production, update the database settings:
spring.datasource.url=jdbc:postgresql://localhost:5432/payment_agent
spring.datasource.username=your_db_user
spring.datasource.password=your_db_password
spring.datasource.driver-class-name=org.postgresql.Driver- POST
/api/v1/auth/token- Exchange API key for JWT Bearer token - GET
/api/v1/auth/validate- Validate current JWT token
- POST
/api/v1/purchase- Initiate a payment (requires Bearer token) - POST
/api/v1/purchase/{transactionId}/override- Override a denied payment (requires Bearer token)
-
Get JWT Token:
curl -X POST http://localhost:8080/api/v1/auth/token \ -H 'Content-Type: application/json' \ -d '{"apiKey":"test"}'
-
Make Purchase (copy accessToken from step 1):
curl -X POST http://localhost:8080/api/v1/purchase \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer YOUR_TOKEN" \ -d '{ "amount": 50, "merchant": "udemy", "productType": "course", "productId": "python-advanced", "currency": "USD" }'
-
Test Denial (exceeds limits):
curl -X POST http://localhost:8080/api/v1/purchase \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer YOUR_TOKEN" \ -d '{ "amount": 2000, "merchant": "physical_store", "productType": "hardware", "currency": "USD" }'
Run tests with:
mvnw testmvnw clean package