Overview
Permission Mongo uses JSON Web Tokens (JWT) for authentication. All API endpoints (except health checks) require a valid JWT token in the Authorization header.
Authentication Flow
- Obtain a JWT token from your identity provider
- Include the token in the
Authorization header with Bearer prefix
- The server validates the token signature and claims
- Requests are authorized based on JWT claims (tenant, roles, etc.)
Include the JWT token in the Authorization header:
Authorization: Bearer <your_jwt_token>
Example Request
curl -X GET “http://localhost:8080/users”
-H “Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…”
JWT Configuration
Permission Mongo supports two JWT signing algorithms:
RS256 (RSA with SHA-256)
Recommended for production. Uses asymmetric public/private key pairs.
auth:
algorithm: RS256
public_key_file: /path/to/public_key.pem
public_key: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA…
-----END PUBLIC KEY-----
issuer: “https://your-auth-provider.com”
audience: “permission-mongo-api”
HS256 (HMAC with SHA-256)
Simpler configuration using a shared secret. Suitable for development.
auth:
algorithm: HS256
secret: “your-secret-key-here”
issuer: “https://your-auth-provider.com”
audience: “permission-mongo-api”
JWT Claims
Permission Mongo validates and extracts these JWT claims:
Subject - unique user identifier
Tenant identifier for multi-tenancy isolation
Array of role strings (e.g., ["admin", "editor"])
Issuer - must match configured issuer
Audience - must include configured audience
Expiration time (Unix timestamp)
Issued at time (Unix timestamp)
Example JWT Payload
{
"sub": "user_123456",
"tenant_id": "tenant_abc",
"roles": ["admin", "editor"],
"department": "engineering",
"iss": "https://auth.example.com",
"aud": "permission-mongo-api",
"exp": 1735689600,
"iat": 1735686000
}
Token Validation
The server validates:
- Signature: Verifies token was signed by trusted issuer
- Algorithm: Ensures algorithm matches configuration (RS256 or HS256)
- Expiration: Checks token hasn’t expired (
exp claim)
- Issuer: Validates
iss claim matches configuration
- Audience: Ensures
aud claim includes configured audience
- Required Claims: Verifies
sub claim is present
Authentication Context
After successful authentication, the server creates an auth context available to all handlers:
type AuthContext struct {
UserID string // From 'sub' claim
TenantID string // From 'tenant_id' claim
Roles []string // From 'roles' claim
Claims map[string]interface{} // All JWT claims
}
This context is used for:
- Multi-tenant data isolation
- Role-based access control (RBAC)
- Audit logging
- Custom permission checks
Error Responses
curl -X GET “http://localhost:8080/users”
```json
{
"error": {
"code": "UNAUTHORIZED",
"message": "missing authorization header"
},
"meta": {
"request_id": "e1f2a3b4c5d6"
}
}
Status Code: 401 Unauthorized
curl -X GET “http://localhost:8080/users”
-H “Authorization: InvalidToken”
{
"error": {
"code": "UNAUTHORIZED",
"message": "invalid authorization header format"
},
"meta": {
"request_id": "f2a3b4c5d6e7"
}
}
**Status Code**: `401 Unauthorized`
### Expired Token
curl -X GET "http://localhost:8080/users" \
-H "Authorization: Bearer <expired_token>"
```json
{
"error": {
"code": "EXPIRED_TOKEN",
"message": "token has expired"
},
"meta": {
"request_id": "a3b4c5d6e7f8"
}
}
**Status Code**: `401 Unauthorized`
### Invalid Signature
```json
{
"error": {
"code": "INVALID_TOKEN",
"message": "invalid token signature"
},
"meta": {
"request_id": "b4c5d6e7f8a9"
}
}
**Status Code**: `401 Unauthorized`
### Invalid Issuer
```json
{
"error": {
"code": "INVALID_TOKEN",
"message": "invalid token issuer"
},
"meta": {
"request_id": "c5d6e7f8a9b0"
}
}
**Status Code**: `401 Unauthorized`
### Invalid Audience
```json
{
"error": {
"code": "INVALID_TOKEN",
"message": "invalid token audience"
},
"meta": {
"request_id": "d6e7f8a9b0c1"
}
}
**Status Code**: `401 Unauthorized`
## Token Generation
Permission Mongo does not generate JWT tokens. You must obtain tokens from your identity provider (e.g., Auth0, Keycloak, custom OAuth server).
### Example Token Generation (External)
Using a Node.js library:
const jwt = require('jsonwebtoken');
const fs = require('fs');
// For RS256
const privateKey = fs.readFileSync('private_key.pem');
const token = jwt.sign(
{
sub: 'user_123456',
tenant_id: 'tenant_abc',
roles: ['admin'],
department: 'engineering'
},
privateKey,
{
algorithm: 'RS256',
expiresIn: '1h',
issuer: 'https://auth.example.com',
audience: 'permission-mongo-api'
}
);
console.log(token);
For HS256:
const token = jwt.sign(
{
sub: 'user_123456',
tenant_id: 'tenant_abc',
roles: ['admin']
},
'your-secret-key-here',
{
algorithm: 'HS256',
expiresIn: '1h',
issuer: 'https://auth.example.com',
audience: 'permission-mongo-api'
}
);
## Development Mode
<Warning>
**Never use development mode in production!** It bypasses all authentication.
</Warning>
For local development and testing, you can bypass authentication:
export PM_DEV_MODE=true
export PM_DEV_TENANT_ID=000000000000000000000001
In dev mode:
- All requests are authenticated as an admin user
- No `Authorization` header required
- Tenant ID is set to `PM_DEV_TENANT_ID`
- Logs show "Dev mode enabled" warning
### Dev Mode Request
# No Authorization header needed in dev mode
curl -X GET "http://localhost:8080/users"
## Best Practices
1. **Use RS256 in Production**: More secure than HS256
2. **Short Token Expiry**: Recommend 1 hour or less
3. **Rotate Keys Regularly**: Update public keys periodically
4. **Validate Issuer**: Always configure and validate the `iss` claim
5. **Use HTTPS**: Encrypt tokens in transit
6. **Include Tenant ID**: Required for multi-tenant isolation
7. **Minimal Claims**: Only include necessary claims in JWT
8. **Token Refresh**: Implement refresh token flow in your app
## Troubleshooting
### "Invalid algorithm" Error
Ensure your JWT uses the same algorithm configured in the server (RS256 or HS256).
### "Invalid signature" Error
- For RS256: Verify the public key matches the private key used to sign tokens
- For HS256: Ensure the secret matches on both sides
### "Missing required claims" Error
Ensure your JWT includes the `sub` claim (user ID).
### Permission Denied
Authentication succeeded but authorization failed. Check:
- Tenant ID matches the resource tenant
- User has required roles in the policy
- RBAC rules allow the operation