Go Money uses JWT (JSON Web Tokens) with RSA-256 signing for authentication.
| Feature | Description |
|---|---|
| Algorithm | RS256 (RSA with SHA-256) |
| Token Format | JWT (RFC 7519) |
| Token Types | Web tokens (short-lived), Service tokens (long-lived) |
| Header | Authorization: Bearer <token> |
Short-lived tokens for interactive sessions.
| Property | Value |
|---|---|
| TTL | 24 hours |
| Token Type | web |
| Use Case | Web UI, interactive sessions |
| Refresh | Re-login required |
Long-lived tokens for programmatic access.
| Property | Value |
|---|---|
| TTL | Custom (set at creation) |
| Token Type | service_token |
| Use Case | API integrations, automation, MCP server |
| Revocable | Yes |
{
"exp": 1704067200,
"jti": "550e8400-e29b-41d4-a716-446655440000",
"user_id": 1,
"token_type": "web"
}| Claim | Type | Description |
|---|---|---|
| exp | number | Expiration timestamp (Unix) |
| jti | string | Unique token identifier (UUID) |
| user_id | int32 | User ID |
| token_type | string | web or service_token |
POST /gomoneypb.users.v1.UsersService/Login
Request:
{
"login": "admin",
"password": "secret"
}Response:
{
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}Include the token in the Authorization header:
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
The first user is created via the Create endpoint. This only works when no users exist.
POST /gomoneypb.users.v1.UsersService/Create
Request:
{
"login": "admin",
"password": "secure_password"
}Response:
{
"id": 1
}Note: After the first user is created, this endpoint returns an error.
Passwords are hashed using bcrypt with a cost factor of 5.
Requires authentication.
POST /gomoneypb.configuration.v1.ConfigurationService/CreateServiceToken
Request:
{
"name": "MCP Integration",
"expires_at": "2025-12-31T23:59:59Z"
}Response:
{
"service_token": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "MCP Integration",
"expires_at": "2025-12-31T23:59:59Z",
"created_at": "2024-01-15T10:30:00Z"
},
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}Important: The token field is only returned once at creation time. Store it securely.
POST /gomoneypb.configuration.v1.ConfigurationService/GetServiceTokens
Request:
{
"ids": []
}Response:
{
"service_tokens": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "MCP Integration",
"expires_at": "2025-12-31T23:59:59Z",
"created_at": "2024-01-15T10:30:00Z"
}
]
}POST /gomoneypb.configuration.v1.ConfigurationService/RevokeServiceToken
Request:
{
"id": "550e8400-e29b-41d4-a716-446655440000"
}Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000"
}Service tokens can be revoked before expiration. The system maintains a revocation list.
- Token JTI is added to
jti_revocationstable - Revocation entry expires 7 days after original token expiry
- Token validation checks revocation list with 5-minute cache
| Setting | Value |
|---|---|
| Cache Size | 1000 entries |
| Cache TTL | 5 minutes |
| Storage | In-memory LRU |
| Column | Type | Description |
|---|---|---|
| id | integer | Primary key (auto-increment) |
| login | text | Username |
| password | text | Bcrypt hash |
| created_at | timestamp | Creation time |
| deleted_at | timestamp | Soft delete marker |
| Column | Type | Description |
|---|---|---|
| id | uuid | Primary key (token JTI) |
| name | text | User-provided name |
| expires_at | timestamp | Expiration time |
| deleted_at | timestamp | Soft delete (revocation) |
| created_at | timestamp | Creation time |
| Column | Type | Description |
|---|---|---|
| id | text | Primary key (JTI) |
| expires_at | timestamp | Entry expiration (7 days after token expiry) |
| Error | Connect Code | Description |
|---|---|---|
| Invalid token | UNAUTHENTICATED | Token parsing or validation failed |
| Token expired | UNAUTHENTICATED | Token past expiration |
| Token revoked | UNAUTHENTICATED | Service token was revoked |
| Permission denied | PERMISSION_DENIED | Valid token but missing user_id |
- RSA private key is configured via
JWT_PRIVATE_KEYenvironment variable - If not provided, a temporary key is generated (not recommended for production)
- Key format: PEM-encoded PKCS#1 RSA private key
- Use HTTPS - Always use TLS in production
- Rotate Keys - Periodically rotate RSA keys
- Short TTL for Web - 24-hour TTL limits exposure
- Revoke Unused Tokens - Regularly audit and revoke service tokens
- Secure Storage - Store service tokens securely (secrets manager, encrypted storage)
| Environment Variable | Description | Default |
|---|---|---|
| JWT_PRIVATE_KEY | RSA private key (PEM) | Auto-generated |
To generate a new RSA key:
openssl genrsa -out private.pem 2048Then set the environment variable:
export JWT_PRIVATE_KEY="$(cat private.pem)"One-liner for environment variables:
openssl genrsa 2048 2>/dev/null | openssl rsa -traditional 2>/dev/null | awk '{printf "%s\\n", $0}'This outputs the key with escaped newlines, suitable for .env files.
Go Money uses Connect protocol (gRPC-compatible HTTP/JSON).
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"key": "value"}' \
http://localhost:8080/gomoneypb.users.v1.UsersService/Login| Endpoint | Description |
|---|---|
| UsersService/Login | User authentication |
| UsersService/Create | First user creation |
| ConfigurationService/GetConfiguration | Public configuration |
All other endpoints require a valid JWT token in the Authorization header.
- Endpoints - All API endpoints
- users Table - User schema
- INDEX - Full documentation index