The ETIS Auth Provider exposes a simple REST API for exchanging iCal tokens for JWT tokens.
Base URL: http://localhost:8080 (default)
Client → POST /auth with iCal token → JWT token
Client → Use JWT for protected resources
Exchange a valid 16-character iCal token for a JWT token.
Request Methods:
- JSON Body:
POST /auth HTTP/1.1
Content-Type: application/json
{
"token": "1234567890abcdef"
}- Authorization Header:
POST /auth HTTP/1.1
Authorization: Bearer 1234567890abcdefSuccess Response (200 OK):
{
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDcwNzIzMDAsImlhdCI6MTcwNzA2ODcwMCwic3ViIjoiYTY2NWExNDU5MjAxZDJkYzc4NTNjNWY4MzgxMWI0ZjEzZmE3YzhlNDNmZTdlZmM5MGQxNDNlYjE2ZTg4YmY0YiJ9.signature"
}JWT Payload Structure:
{
"sub": "a665a14592...", // SHA256 hash of the iCal token
"iat": 1707068700, // Issued at (Unix timestamp)
"exp": 1707072300 // Expiration (Unix timestamp)
}Error Responses:
| Status Code | Error | Description |
|---|---|---|
| 400 | {"error":"Token required"} |
No token provided in request |
| 400 | {"error":"Invalid JSON"} |
Malformed JSON body |
| 401 | {"error":"Invalid token"} |
Token validation failed (wrong length, format, or not found on upstream) |
| 429 | {"error":"Rate limit exceeded"} |
Too many requests |
| 500 | {"error":"Failed to generate token"} |
Internal server error during JWT generation |
| 500 | {"error":"Validation failed"} |
Unexpected error during validation |
| 503 | {"error":"Upstream service unavailable"} |
ETIS iCal service is not available (network error, timeout, server error) |
Rate Limiting:
- Global rate limit (default: 100 requests per 60 seconds)
- Per-IP rate limit (default: 10 requests per 60 seconds per IP)
Example Request:
curl -X POST http://localhost:8080/auth \
-H "Content-Type: application/json" \
-d '{"token":"1234567890abcdef"}'Example with Authorization Header:
curl -X POST http://localhost:8080/auth \
-H "Authorization: Bearer 1234567890abcdef"JWK (JSON Web Key) endpoint for KrakenD JWT validation. Returns the public key information in JWK format for validating JWT tokens signed by this service.
Response (200 OK):
{
"keys": [
{
"kty": "oct",
"alg": "HS256",
"k": "base64url-encoded-secret",
"kid": "auto-generated-key-id"
}
]
}Example:
curl http://localhost:8080/jwkUsage with KrakenD:
This endpoint should be configured in KrakenD's auth/validator section:
{
"extra_config": {
"auth/validator": {
"alg": "HS256",
"jwk_url": "http://etis-auth-provider:8080/jwk",
"cache": true,
"cache_duration": 3600,
"disable_jwk_security": true
}
}
}Notes:
- The
kid(Key ID) is automatically generated from the secret hash - KrakenD will cache the JWK response for the configured duration
disable_jwk_security: trueis required for symmetric keys (HS256)- The same
JWT_SECRETmust be used in both services
Health check endpoint for monitoring and liveness probes.
Response (200 OK):
{
"status": "ok"
}Example:
curl http://localhost:8080/healthReadiness check endpoint for Kubernetes readiness probes.
Response (200 OK):
{
"status": "ok"
}Example:
curl http://localhost:8080/readyThe service supports CORS for cross-origin requests:
- Allowed Methods: GET, POST, OPTIONS
- Allowed Headers: Authorization, Content-Type
- Max Age: 86400 seconds (24 hours)
OPTIONS Preflight:
curl -X OPTIONS http://localhost:8080/auth \
-H "Origin: https://example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: Authorization"All errors follow this format:
{
"error": "Error message"
}Common HTTP status codes:
200- Success400- Bad Request (client error)401- Unauthorized (invalid token)405- Method Not Allowed429- Too Many Requests (rate limit exceeded)500- Internal Server Error503- Service Unavailable (upstream service unreachable)
- Length: Token must be exactly 16 characters
- Format: Any alphanumeric characters
- Validation: Token is validated against upstream ETIS service (ical.psu.ru)
- Caching: Valid tokens are cached for the configured duration (default: 3600 seconds)
- Algorithm: HS256 (HMAC-SHA256)
- Secret: Configured via
JWT_SECRETenvironment variable
sub(Subject): SHA256 hash of the iCal token (64 hex characters)iat(Issued At): Unix timestamp when JWT was issuedexp(Expiration): Unix timestamp when JWT expires (default: iat + 3600 seconds)
To verify JWT tokens in your application:
Go:
import "github.com/golang-jwt/jwt/v5"
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method")
}
return []byte("your-jwt-secret"), nil
})Node.js:
const jwt = require('jsonwebtoken');
jwt.verify(token, 'your-jwt-secret', (err, decoded) => {
if (err) {
console.error('Invalid token');
} else {
console.log(decoded.sub); // Token hash
}
});Python:
import jwt
try:
payload = jwt.decode(token, 'your-jwt-secret', algorithms=['HS256'])
print(payload['sub']) # Token hash
except jwt.InvalidTokenError:
print('Invalid token')- Always use HTTPS in production to protect tokens in transit
- Keep JWT_SECRET secure - use strong, randomly generated secrets
- Tokens are cached - revocation is not immediate (cache TTL applies)
- Rate limiting - protects against brute force attacks
- Token hash in JWT - original iCal token is never stored in JWT
See examples/test-requests.sh for comprehensive testing examples.
Quick test:
# Health check
curl http://localhost:8080/health
# Test auth (will fail with invalid token)
curl -X POST http://localhost:8080/auth \
-H "Content-Type: application/json" \
-d '{"token":"1234567890abcdef"}'