JWT authentication provider service for ETIS iCal token validation. Designed for deployment in Kubernetes clusters to provide authentication for web resources.
- Token Validation: Validates 16-character iCal tokens against upstream ETIS service (ical.psu.ru)
- JWT Generation: Exchanges valid iCal tokens for JWT tokens with SHA256 token hash, issue time, and expiration
- KrakenD Compatible: Full support for KrakenD CE JWT validation with JWK endpoint
- Production Ready: Built-in rate limiting, caching, logging, and graceful shutdown
- Kubernetes Native: Health probes, ConfigMaps, Secrets, and security best practices
- JWK Endpoint: Provides JSON Web Key endpoint for symmetric key validation
- API Documentation - Complete API reference
- KrakenD Integration Guide - Detailed integration with KrakenD API Gateway
- Error Handling Guide - Comprehensive error handling documentation
- Deployment Guide - Kubernetes deployment instructions
- Examples - Configuration examples and test scripts
# Build and run
make build
export JWT_SECRET=your-secret-key
./etis-auth-provider
# Or use Docker
docker build -t etis-auth-provider .
docker run -p 8080:8080 -e JWT_SECRET=your-secret-key etis-auth-providerdocker-compose upExchange iCal token for JWT token.
Request (JSON body):
{
"token": "1234567890abcdef"
}Or (Authorization header):
Authorization: Bearer 1234567890abcdef
Response:
{
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Error Response:
{
"error": "Invalid token"
}JWK (JSON Web Key) endpoint for KrakenD integration.
Response:
{
"keys": [
{
"kty": "oct",
"alg": "HS256",
"k": "base64url-encoded-secret",
"kid": "auto-generated-key-id"
}
]
}Health check endpoint (liveness probe).
Response:
{
"status": "ok"
}Readiness check endpoint.
Response:
{
"status": "ok"
}All configuration is done via environment variables:
| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
Service port |
UPSTREAM_URL |
https://ical.psu.ru/calendars/ |
iCal validation endpoint |
JWT_SECRET |
change-me-in-production |
Secret key for JWT signing (required in production) |
JWT_EXPIRATION |
3600 |
JWT expiration time in seconds |
CACHE_FRESHNESS |
3600 |
Token cache TTL in seconds |
TIMEOUT |
10 |
Upstream request timeout in seconds |
LOG_LEVEL |
info |
Logging level: error/info/debug |
RATE_LIMIT_GLOBAL |
100 |
Global requests per window |
RATE_LIMIT_PER_IP |
10 |
Per-IP requests per window |
RATE_LIMIT_WINDOW |
60 |
Rate limit window in seconds |
CLEANUP_INTERVAL |
300 |
Cleanup interval in seconds |
TLS_SKIP_VERIFY |
false |
Skip TLS certificate verification (use only if upstream has self-signed cert) |
- Kubernetes cluster (1.19+)
- kubectl configured
- Docker image built and available to cluster
- Create a custom JWT secret:
kubectl create secret generic etis-auth-provider-secret \
--from-literal=JWT_SECRET=$(openssl rand -base64 32)- Deploy the service:
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secret.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml- Optional: Deploy Ingress for external access:
# Edit k8s/ingress.yaml and change auth.example.com to your domain
kubectl apply -f k8s/ingress.yaml- Optional: Apply NetworkPolicy for security:
kubectl apply -f k8s/networkpolicy.yaml# Check pod status
kubectl get pods -l app=etis-auth-provider
# Check logs
kubectl logs -l app=etis-auth-provider
# Test health endpoint
kubectl port-forward svc/etis-auth-provider 8080:8080
curl http://localhost:8080/healthThis service is fully compatible with KrakenD CE JWT validation. The service provides a JWK (JSON Web Key) endpoint that KrakenD can use to validate JWT tokens.
1. Configure KrakenD to use the JWK endpoint:
{
"endpoint": "/protected",
"extra_config": {
"auth/validator": {
"alg": "HS256",
"jwk_url": "http://etis-auth-provider:8080/jwk",
"cache": true,
"cache_duration": 3600,
"operation_debug": true,
"disable_jwk_security": true
}
}
}2. Authentication Flow:
1. Client → POST /auth (with iCal token) → Receive JWT token
2. Client → Request protected endpoint with JWT → KrakenD validates JWT → Backend service
Minimal setup with authentication:
- Login endpoint proxies to
/auth - Protected endpoint validates JWT using JWK endpoint
Production-ready setup with:
- Rate limiting: IP-based rate limits on authentication
- Claim propagation: Pass JWT claims as HTTP headers to backend
- CORS support: Configurable cross-origin access
- Health checks: Gateway health monitoring
- Error handling: Detailed error responses
JWK Endpoint (/jwk):
- Returns symmetric key in JWK format
- Automatically generates
kid(key ID) from secret hash - Compatible with KrakenD's JWT validator
- Cacheable (recommended TTL: 3600 seconds)
JWT Token Format:
{
"alg": "HS256",
"typ": "JWT",
"kid": "auto-generated-key-id"
}
{
"sub": "token-hash",
"iat": 1234567890,
"exp": 1234571490
}Claim Propagation: KrakenD can forward JWT claims as HTTP headers to your backend:
"propagate_claims": [
["sub", "X-User-Token-Hash"],
["iat", "X-Token-Issued-At"],
["exp", "X-Token-Expires-At"]
]For internal cluster communication:
http://etis-auth-provider:8080/auth (authentication)
http://etis-auth-provider:8080/jwk (JWK endpoint for validation)
disable_jwk_security: trueis required for symmetric keys (HS256)- Same secret must be used in both services (use Kubernetes Secrets)
- Cache JWK endpoint in KrakenD to reduce load
operation_debug: truehelps troubleshoot JWT validation issues
# Get JWT token
TOKEN=$(curl -X POST http://localhost:8080/auth \
-H "Content-Type: application/json" \
-d '{"token":"your-ical-token"}' | jq -r '.jwt')
# Use token with KrakenD protected endpoint
curl http://localhost:8000/api/protected \
-H "Authorization: Bearer $TOKEN"
# Check JWK endpoint
curl http://localhost:8080/jwkSee examples/ directory for complete KrakenD configuration examples.
If you encounter certificate verification errors like:
x509: certificate signed by unknown authority
This happens when the upstream server's certificate chain is incomplete or uses a CA not in your system's trust store.
Solution:
Set TLS_SKIP_VERIFY=true environment variable:
docker run -e TLS_SKIP_VERIFY=true ...Or in Kubernetes:
env:
- name: TLS_SKIP_VERIFY
value: "true"TLS_SKIP_VERIFY=true if you trust the upstream server (e.g., internal network). For production with external upstreams, consider adding the CA certificate to your system's trust store instead.
- Stateless: In-memory cache only, no persistent state (horizontally scalable)
- 12-Factor App: Configuration via environment variables, logs to stdout
- Security: Non-root container, read-only filesystem, minimal capabilities
- Observability: Structured logging with configurable levels
# Format code
make fmt
# Run linters
make vet
# Build
make build
# Clean
make cleanMIT