Authentication
EvidentSource uses a delegated authentication model where credential validation happens at the network edge, and the application trusts pre-validated claims from the edge layer.
Trust Model
Section titled “Trust Model” ┌─────────────────────────────────────────────────────┐ │ UNTRUSTED NETWORK │ │ │ │ ┌──────────┐ ┌──────────┐ │ │ │ Client │ │ Client │ │ │ │ (JWT) │ │ (JWT) │ │ │ └────┬─────┘ └────┬─────┘ │ │ │ │ │ └────────┼───────────────────┼────────────────────────┘ │ │ ▼ ▼┌──────────────────────────────────────────────────────────────────────────────┐│ EDGE LAYER (Trust Boundary) ││ ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ AWS Application Load Balancer │ ││ │ │ ││ │ • Validates JWT signatures against JWKS endpoint │ ││ │ • Verifies issuer (iss) and audience (aud) claims │ ││ │ • Checks token expiration (exp) │ ││ │ • Returns 401 for invalid/missing tokens │ ││ │ │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ │ │└────────────────────────────────────┼──────────────────────────────────────────┘ │ Pre-validated JWT │ (Authorization header) ▼┌──────────────────────────────────────────────────────────────────────────────┐│ PRIVATE NETWORK (Trusted) ││ ││ ┌─────────────────────────────────────────────────────────────────────┐ ││ │ EvidentSource Server │ ││ │ │ ││ │ • Parses JWT claims (no signature verification) │ ││ │ • Extracts evs:grants for authorization │ ││ │ • Network isolation ensures only ALB can reach server │ ││ │ │ ││ └─────────────────────────────────────────────────────────────────────┘ ││ │└──────────────────────────────────────────────────────────────────────────────┘Why This Model?
Section titled “Why This Model?”- Separation of concerns: Edge layer handles cryptographic validation; application handles business logic
- Performance: No redundant signature verification at the application layer
- Simplicity: Application doesn’t need to manage JWKS endpoints or key rotation
- Security: Network isolation is the trust boundary, enforced by AWS security groups
JWT Contract
Section titled “JWT Contract”EvidentSource expects JWTs with the following structure:
{ "iss": "https://auth.example.com", "sub": "user-123", "exp": 1735689600, "email": "user@example.com", "name": "Alice Smith", "evs:grants": { "global": ["database_creator"], "databases": { "production": ["reader", "writer"], "staging": ["reader", "writer", "deployer"] }, "all_databases": ["reader"] }}Required Claims
Section titled “Required Claims”| Claim | Description |
|---|---|
sub | Subject identifier (user ID, service account ID) |
exp | Expiration timestamp (Unix epoch) |
Optional Claims
Section titled “Optional Claims”| Claim | Description |
|---|---|
iss | Issuer (validated by ALB JWT Verification) |
email | User email for display/attribution |
name | Display name for attribution |
evs:grants | Authorization grants (see Authorization) |
evs:principal | Structured identity metadata for audit trails |
evs:principal Claim (Optional)
Section titled “evs:principal Claim (Optional)”The evs:principal claim provides structured identity metadata for comprehensive audit trails:
{ "evs:principal": { "type": "human", "name": "Alice Chen", "email": "alice@example.com", "provider": "okta", "upstream_id": "okta|00u1234567890abcdef" }}Principal Types
Section titled “Principal Types”| Type | Description | Use Case |
|---|---|---|
human | Interactive user via OIDC | Developers, operators, analysts |
agent | AI/automation with delegated authority | Claude, GitHub Copilot, custom agents |
system | Service account | Backend APIs, orchestration systems |
Agent Delegation
Section titled “Agent Delegation”For AI agents acting on behalf of a human, include the delegator information:
{ "sub": "agent:claude-assistant-alice", "iss": "https://auth.customer.com", "evs:grants": { "databases": { "development": ["reader", "writer"] } }, "evs:principal": { "type": "agent", "name": "Claude Assistant", "provider": "anthropic", "delegator": { "subject": "user:alice@example.com", "name": "Alice Chen" } }}When an agent makes changes, both the agent and the delegating human are recorded in the event audit trail.
System Service Accounts
Section titled “System Service Accounts”System principals represent backend services and APIs:
{ "sub": "service:order-api", "iss": "https://auth.customer.com", "evs:grants": { "databases": { "orders": ["reader", "writer"] } }, "evs:principal": { "type": "system", "name": "Order API", "provider": "aws_iam", "upstream_id": "arn:aws:iam::123456789:role/order-api" }}Edge Authentication Patterns
Section titled “Edge Authentication Patterns”Pattern 1: ALB JWT Verification (Recommended)
Section titled “Pattern 1: ALB JWT Verification (Recommended)”The EvidentSource CloudFormation template includes optional ALB JWT Verification. When enabled, the ALB validates JWT signatures before forwarding requests.
CloudFormation Parameters:
| Parameter | Description |
|---|---|
JwtIssuer | Expected JWT issuer (e.g., https://auth.example.com) |
JwtJwksEndpoint | JWKS endpoint URL (e.g., https://auth.example.com/.well-known/jwks.json) |
JwtAudience | Expected audience claim (optional) |
How it works:
- Client sends request with
Authorization: Bearer <jwt>header - ALB validates JWT signature against JWKS endpoint
- ALB verifies issuer and audience claims
- ALB forwards valid requests; rejects invalid tokens with 401
- EvidentSource parses claims and enforces authorization
Algorithm requirement: ALB JWT Verification only supports RS256. Ensure your IdP signs tokens with RS256.
Pattern 2: API Gateway with JWT Authorizer
Section titled “Pattern 2: API Gateway with JWT Authorizer”For deployments using API Gateway instead of ALB:
# API Gateway JWT AuthorizerJwtAuthorizer: Type: AWS::ApiGatewayV2::Authorizer Properties: ApiId: !Ref ApiGateway AuthorizerType: JWT IdentitySource: - "$request.header.Authorization" JwtConfiguration: Issuer: !Ref JwtIssuer Audience: - !Ref JwtAudiencePattern 3: Token Vending Service
Section titled “Pattern 3: Token Vending Service”For IdPs that cannot add the evs:grants claim directly, deploy a Lambda-based token vending service that exchanges IdP tokens for EvidentSource-compatible JWTs.
See Token Vending for implementation details.
Server Configuration
Section titled “Server Configuration”CLI Arguments
Section titled “CLI Arguments”./evidentsource server \ --require-auth true \ in-memoryEnvironment Variables
Section titled “Environment Variables”| Variable | Default | Description |
|---|---|---|
EVS_REQUIRE_AUTH | false | Require authentication for all requests |
Authentication Modes
Section titled “Authentication Modes”| Mode | --require-auth | Use Case |
|---|---|---|
| Production | true | All requests must include a valid JWT |
| DevMode | false | Anonymous access allowed (local development only) |
SDK Authentication
Section titled “SDK Authentication”All EvidentSource SDKs support bearer token authentication:
use evidentsource_client::{EvidentSource, Credentials};
let token = std::env::var("EVS_TOKEN")?;let es = EvidentSource::connect_with_auth( "https://api.example.com:50051", Credentials::BearerToken(token),).await?;creds := evidentsource.BearerTokenCredentials{Token: os.Getenv("EVS_TOKEN")}client, err := evidentsource.Connect(ctx, "api.example.com:50051", creds)TypeScript
Section titled “TypeScript”const es = await EvidentSource.connect( 'api.example.com:50051', Credentials.bearerToken(process.env.EVS_TOKEN));var token = Environment.GetEnvironmentVariable("EVS_TOKEN");var client = await EvidentSource.ConnectAsync( "api.example.com:50051", Credentials.BearerToken(token));Python
Section titled “Python”import osfrom evidentsource import EvidentSource, BearerTokenCredentials
token = os.environ["EVS_TOKEN"]es = await EvidentSource.connect( "api.example.com:50051", BearerTokenCredentials(token))Troubleshooting
Section titled “Troubleshooting”401 Unauthorized
Section titled “401 Unauthorized”| Symptom | Cause | Solution |
|---|---|---|
JWT validation failed | Invalid JWT signature | Check IdP signs with RS256; verify JWKS endpoint |
Token expired | JWT exp claim in the past | Refresh token or check clock sync |
Missing issuer | JWT iss doesn’t match | Verify JwtIssuer parameter matches token |
403 Forbidden
Section titled “403 Forbidden”See Authorization for permission-related issues.
Debug Logging
Section titled “Debug Logging”RUST_LOG=evidentsource_server::auth=debug ./evidentsource server ...