Skip to content

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.

┌─────────────────────────────────────────────────────┐
│ 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 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
  1. Separation of concerns: Edge layer handles cryptographic validation; application handles business logic
  2. Performance: No redundant signature verification at the application layer
  3. Simplicity: Application doesn’t need to manage JWKS endpoints or key rotation
  4. Security: Network isolation is the trust boundary, enforced by AWS security groups

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"]
}
}
ClaimDescription
subSubject identifier (user ID, service account ID)
expExpiration timestamp (Unix epoch)
ClaimDescription
issIssuer (validated by ALB JWT Verification)
emailUser email for display/attribution
nameDisplay name for attribution
evs:grantsAuthorization grants (see Authorization)
evs:principalStructured identity metadata for audit trails

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"
}
}
TypeDescriptionUse Case
humanInteractive user via OIDCDevelopers, operators, analysts
agentAI/automation with delegated authorityClaude, GitHub Copilot, custom agents
systemService accountBackend APIs, orchestration systems

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 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"
}
}
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:

ParameterDescription
JwtIssuerExpected JWT issuer (e.g., https://auth.example.com)
JwtJwksEndpointJWKS endpoint URL (e.g., https://auth.example.com/.well-known/jwks.json)
JwtAudienceExpected audience claim (optional)

How it works:

  1. Client sends request with Authorization: Bearer <jwt> header
  2. ALB validates JWT signature against JWKS endpoint
  3. ALB verifies issuer and audience claims
  4. ALB forwards valid requests; rejects invalid tokens with 401
  5. 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 Authorizer
JwtAuthorizer:
Type: AWS::ApiGatewayV2::Authorizer
Properties:
ApiId: !Ref ApiGateway
AuthorizerType: JWT
IdentitySource:
- "$request.header.Authorization"
JwtConfiguration:
Issuer: !Ref JwtIssuer
Audience:
- !Ref JwtAudience

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.

Terminal window
./evidentsource server \
--require-auth true \
in-memory
VariableDefaultDescription
EVS_REQUIRE_AUTHfalseRequire authentication for all requests
Mode--require-authUse Case
ProductiontrueAll requests must include a valid JWT
DevModefalseAnonymous access allowed (local development only)

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)
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));
import os
from evidentsource import EvidentSource, BearerTokenCredentials
token = os.environ["EVS_TOKEN"]
es = await EvidentSource.connect(
"api.example.com:50051",
BearerTokenCredentials(token)
)
SymptomCauseSolution
JWT validation failedInvalid JWT signatureCheck IdP signs with RS256; verify JWKS endpoint
Token expiredJWT exp claim in the pastRefresh token or check clock sync
Missing issuerJWT iss doesn’t matchVerify JwtIssuer parameter matches token

See Authorization for permission-related issues.

Terminal window
RUST_LOG=evidentsource_server::auth=debug ./evidentsource server ...