Authentication provider web service written in Go. Exposes both a JSON REST API and a gRPC server for user creation, authentication, JWT management, user actions, and realm-based namespacing.
- GOAuTh
- Go 1.25+
- PostgreSQL (or Docker for a containerized instance)
# Install git hooks (run once)
make install
# Start the dev PostgreSQL container and run GOAuTh with hot-reload
make devGOAuTh will start two servers concurrently:
- HTTP API on the configured
API_PORT(default:8100) - gRPC server on the configured
RPC_PORT(default:9100)
Both servers shut down gracefully on SIGINT / SIGTERM.
Environment variables can be provided through a .env file in GOAuTh's working directory (loaded via godotenv).
| Variable | Description | Example |
|---|---|---|
DB_PATH |
PostgreSQL connection string | postgres://user:pass@localhost:5432/mydb |
DB_SCHEMA |
Database schema name | users (falls back to public if empty) |
| Variable | Default | Description |
|---|---|---|
API_PORT |
8100 |
HTTP API listen port |
RPC_PORT / GRPC_PORT |
9100 |
gRPC listen port |
JWT_SECRET |
— | Secret used for JWT HS256 signing |
PASSWD_SALT |
— | Salt used for Argon2 password hashing |
DB_LOG_LEVEL |
error |
GORM log level (info, warn, error) |
DB_SLOW_QUERY_LOG_MS |
20 |
Slow query threshold in milliseconds |
Security note:
JWT_SECRETandPASSWD_SALTshould be provided via system environment variables or a secrets manager in production. The.envfile is only suitable for development.
- JWT expiration: 24 hours
- JWT refresh window: 4 weeks
- Argon2 parameters: time=3, memory=32 MiB, threads=4, keyLen=32 (RFC draft defaults)
- Minimum password length: 4 characters
- Login constraint: must be a valid email address
All routes are prefixed with /identity/v1.
| Method | Route | Description |
|---|---|---|
POST |
/identity/v1/auth/signup |
Create a new user |
PUT |
/identity/v1/auth/login |
Authenticate a user |
GET |
/identity/v1/jwt/status |
Check JWT validity |
PUT |
/identity/v1/jwt/refresh |
Refresh an expired JWT |
PUT |
/identity/v1/user/password |
Change password |
PUT |
/identity/v1/user/login |
Change login (email) |
DELETE |
/identity/v1/user/deactivate |
Soft-delete a user |
GET |
/identity/healthcheck |
Health check |
All requests are tagged with an X-Request-ID header (generated if missing). Authenticated endpoints expect an Authorization cookie containing Bearer {JWT}.
Defined in proto/rpc_v1.proto.
| RPC | Description |
|---|---|
Signup(UserRequest) → Response |
Create a new user |
Login(UserRequest) → Response |
Authenticate a user |
Delete(AuthIdRequest) → Response |
Delete a user by ID |
| RPC | Description |
|---|---|
Status(Empty) → Response |
Check JWT validity |
Refresh(Empty) → Response |
Refresh an expired JWT |
| RPC | Description |
|---|---|
Deactivate(Empty) → Response |
Soft-delete a user |
EditUser(EditUserRequest) → Response |
Change login/password |
| RPC | Description |
|---|---|
Create(UserActionRequest) → Response |
Create a user action |
Validate(UserActionValidation) → Response |
Validate a user action |
Status(UserActionRequest) → UserActionStatusResponse |
Get user action status |
JWT is passed via a set-cookie gRPC metadata entry containing Authorization=Bearer {JWT}.
JSON:
{
"login": "user@example.com",
"password": "s3cure!",
"realm_name": "my-realm"
}Protobuf:
message UserRequest {
string login = 1;
string password = 2;
string realm = 3;
}JSON (password change):
{
"password": "current-password",
"new_password": "new-s3cure!"
}JSON (login change):
{
"password": "current-password",
"login": "old@example.com",
"new_login": "new@example.com"
}Protobuf:
message EditUserRequest {
string new_login = 1;
string new_password = 2;
string password = 3;
}No JSON body. Requires an Authorization cookie (HTTP) or set-cookie metadata (gRPC) containing Bearer {JWT}.
message UserActionRequest {
string login = 1;
string realm = 2;
string action = 3;
string data = 4;
}
message UserActionValidation {
string realm = 1;
string data = 2;
string against = 3;
}bin/GOAuTh/ → Main binary (HTTP + gRPC servers)
internal/
api/handlers/ → HTTP route handlers (auth, jwt, user)
config/boot/ → Bootstrap (DB, JWT factory, user params)
config/consts/ → Environment variable names, defaults, error codes
config/middleware/ → Request logging, X-Request-ID (HTTP & gRPC)
domain/entities/ → GORM models (User, Realm, UserAction), constraints
domain/models/ → UsersParams (salt, Argon2 config, constraints)
domain/services/ → Business logic (auth, jwt, user, user actions)
pkg/
crypt/ → Argon2 hashing, JWT encode/decode (HS256)
data_types/ → Utility types (ptr, slice, tuple)
domain/entities/ → Generic interfaces (User, JWT)
errors/ → Error type with HTTP status mapping
grpc/v1/ → gRPC server implementations + generated code
http/ → Middleware, JSON request/response, RPC cookie helpers
plugins/ → Event-based plugin system (before/after hooks)
plugins/ → Loadable plugin files (e.g. heyo broker integration)
proto/ → Protocol Buffer definitions
- DDD-ish / Clean Architecture: domain entities and services are separated from transport (HTTP/gRPC) handlers.
- Realm-based namespacing: users belong to realms, allowing multi-tenant setups.
- Dual transport: the same service layer is exposed over both HTTP and gRPC.
- Plugin system: event hooks (
OnUserCreation, etc.) with configurable timeouts for extensibility. - Graceful shutdown:
oklog/runcoordinates concurrent servers and OS signal handling.
docker compose up -d # Starts PostgreSQL (dev/dev/dev_db) on port 5432docker build -t drannoc/goauth .The multi-stage Dockerfile builds GOAuTh and the client binary, then runs via an entrypoint script that:
- Waits for PostgreSQL readiness
- Writes a
.envfile from container environment variables - Starts GOAuTh (or a custom command)
# Start containers + hot-reload server (uses gow)
make dev
# Regenerate protobuf code (Go + Rust)
make proto
# Access the dev database via psql
make dpsql# Unit tests only (internal, pkg, plugins)
make unit-test
# Full test suite (spins up a test DB container, runs all tests)
make test
# Manually manage the test database container
make run-test-db
make stop-test-db| Target | Description |
|---|---|
help |
Show available targets |
install |
Install git pre-commit hook |
all_up |
Start all Docker Compose services |
db_layout |
Start DB container + import initial SQL |
dev |
Start Docker + hot-reload GOAuTh with gow |
unit-test |
Run unit tests |
test |
Run full test suite (with ephemeral test DB) |
run-test-db |
Start a standalone test PostgreSQL container |
stop-test-db |
Stop the standalone test PostgreSQL container |
proto-go |
Regenerate Go protobuf/gRPC code |
proto-rust |
Build Rust protobuf client |
proto |
Regenerate both Go and Rust protobuf code |
docker-build |
Build and push the Docker image |
dpsql |
Open a psql shell to the dev database |
Additional utility binaries live in bin/. Each has its own README:
bin/client/— CLI client for interacting with GOAuTh via API or gRPCbin/min-grpc-server/— Minimal gRPC-only server (no HTTP)bin/spy-token/— JWT token generator for development/debugging