Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 65 additions & 8 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project Overview

BulwarkAuth is an API-based, developer-focused JWT authentication/authorization subsystem written in Go. It provides asymmetric key signing (RS256), passwordless authentication (magic links), password-based authentication, email verification, and social sign-in capabilities (Google in development).
BulwarkAuth is an API-based, developer-focused JWT authentication/authorization subsystem written in Go with built-in multi-tenant support. It provides asymmetric key signing (RS256), passwordless authentication (magic links), password-based authentication, email verification, account lockout protection, and social sign-in capabilities (Google in development).

## Key Architecture

Expand All @@ -20,10 +20,11 @@ The codebase follows a clean architecture pattern with three main layers:

2. **Internal Layer** (`internal/`): Business logic and domain models
- `internal/accounts/`: Account service, repository pattern for accounts and forgot password
- `internal/authentication/`: Authentication service, token repository, logon code (magic links)
- `internal/authentication/`: Authentication service, token repository, logon code (magic links), failed attempts tracking
- `internal/tokens/`: JWT tokenizer, signing key service and repository
- `internal/email/`: Email service with template support
- `internal/encryption/`: Password encryption utilities
- `internal/tenants/`: Tenant service and repository for multi-tenant support
- `internal/utils/`: Transaction manager and test utilities

3. **Entry Point** (`cmd/bulwarkauth/`): Application bootstrap
Expand All @@ -42,21 +43,30 @@ The codebase follows a clean architecture pattern with three main layers:

### Key Components

**Multi-Tenant System** (`internal/tenants/`):
- All accounts, tokens, and signing keys are isolated by tenant ID
- Each tenant has its own signing keys for JWT tokens
- Tenant service manages tenant creation and retrieval
- Use `"default"` tenant ID for single-tenant applications

**Token System** (`internal/tokens/`):
- `Tokenizer`: Creates and validates JWT access/refresh tokens
- `SigningKeyService`: Manages RSA key pairs for JWT signing with rotation support
- `SigningKeyService`: Manages RSA key pairs for JWT signing with rotation support per tenant
- Tokens use RS256 signing with configurable expiration times
- Access tokens contain roles for RBAC, refresh tokens for renewal
- Access tokens contain roles for RBAC and tenant ID, refresh tokens for renewal
- Tokens are scoped to tenants and cannot be used across tenants

**Authentication Flow**:
1. Password auth: `AuthenticationService.Authenticate()` validates credentials, returns tokens
2. Magic link auth: `LogonCodeService.Request()` generates 6-digit code, sends email; `Authenticate()` validates code
1. Password auth: `AuthenticationService.Authenticate()` validates credentials, checks failed attempts, returns tokens
2. Magic link auth: `LogonCodeService.Request()` generates 6-digit code, sends email; `Authenticate()` validates code, checks failed attempts
3. Token acknowledgement: `Acknowledge()` stores tokens per client ID (multi-device support)
4. Token renewal: `Renew()` uses refresh token to get new access/refresh token pair
5. Token revocation: `Revoke()` deletes tokens for a client
6. Account lockout: After 5 failed attempts (configurable), account is locked for a duration (configurable, default 300 seconds)

**Email System** (`internal/email/`):
- Template-based emails (verification, forgot password, magic link)
- Supports tenant-specific email templates via `EMAIL_TEMPLATE_DIRS`
- SMTP configuration via environment variables
- Test mode bypasses actual sending

Expand Down Expand Up @@ -105,11 +115,25 @@ go test -v ./...
mockery --all --output internal/accounts --dir internal/accounts --case underscore
```

### Integration Testing
Integration tests validate the full API using the [bulwark-auth-guard](https://github.com/latebit-io/bulwark-auth-guard) client:
```bash
# Start services with docker-compose
docker-compose up -d

# Run integration tests
go test ./test/integration/... -v

# Stop services
docker-compose down
```

### HTTP Testing
HTTP request files are in `http/` directory:
1. Copy `http/accounts.http.example` to `http/accounts.http`
2. Fill in placeholders (API_KEY, TEST_EMAIL, etc.)
2. Fill in placeholders (API_KEY, TENANT_ID, TEST_EMAIL, etc.)
3. Use REST client (VS Code REST Client, IntelliJ) to execute requests
4. Note: All requests now require `tenantId` in the request body

## Configuration

Expand All @@ -128,19 +152,52 @@ Optional but important:
- `CORS_ENABLED=true` + `ALLOWED_WEB_ORIGINS`: Configure CORS
- `ACCESS_TOKEN_EXPIRE_IN_SECONDS`: Default 3600 (1 hour)
- `REFRESH_TOKEN_EXPIRE_IN_SECONDS`: Default 86400 (24 hours)
- `LOCKOUT_DURATION_IN_SEC`: Account lockout duration in seconds (default 300)
- `MAX_FAILED_ATTEMPTS`: Maximum failed auth attempts before lockout (default 5)
- `EMAIL_TEMPLATE_DIRS`: Comma-separated list of directories for tenant-specific email templates
- `TEST_MODE=true`: Bypass email sending for testing

See `cmd/bulwarkauth/config.go` for complete list.

## Testing Infrastructure

### Unit Tests
The codebase uses `memongo` for in-memory MongoDB testing:
- `internal/utils/mongo_test_util.go`: Helper for creating test MongoDB instances
- Tests use real MongoDB operations against ephemeral instance
- No need for mocking MongoDB in most tests

### Integration Tests
Located in `test/integration/`:
- Uses [bulwark-auth-guard](https://github.com/latebit-io/bulwark-auth-guard) client library
- Tests complete user flows (account creation, authentication, token management)
- Validates multi-tenant support with `tenantId: "default"`
- Requires docker-compose to run (BulwarkAuth, MongoDB, MailHog)
- 13 test cases covering all major features including account lockout

See `test/integration/README.md` for details.

## Multi-Tenant Usage

When using the bulwark-auth-guard client, all API calls require a tenant ID:

```go
const tenantID = "default" // Or your specific tenant ID

// Create account
err := guard.Account.Create(ctx, tenantID, email, password)

// Authenticate
auth, err := guard.Authenticate.Password(ctx, tenantID, email, password, clientID)

// Validate token
claims, err := guard.Authenticate.ValidateAccessToken(ctx, tenantID, accessToken)
```

For single-tenant applications, use `"default"` as the tenant ID.

## Social Authentication (In Development)

Google social sign-in is being added:
- `internal/authentication/social/social-validator.go`: OAuth validation logic
- Feature branch: `feat-google-social-sign-in`
- Requires `GOOGLE_CLIENT_ID` environment variable
72 changes: 64 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# bulwarkauth

Bulwark.Auth is an api based developer focused JWT authentication/authorization subsystem for any infrastructure.
Bulwark.Auth is an api based developer focused JWT authentication/authorization subsystem for any infrastructure with built-in multi-tenant support.

# Releases and contributing guidelines

Expand All @@ -17,20 +17,22 @@ Releases will be rolling as features are developed and tested, then merged into


# Key Features:
- **Multi-tenant support** - Isolate users, accounts, and authentication data by tenant ID
- Asymmetric key signing on JWT tokens can use:
- RS256,
- TODO: RS384
- TODO: RS512
- Plug and play key generation and rotation for jwt signing.
- Plug and play key generation and rotation for jwt signing per tenant
- Deep token validation on the server side checks for revocation, expiration, and more
- TODO: Client side token validation can be used to reduce round trips to the server
- Configurable refresh token and access token expiration
- bulwarkauth does not need to be deployed on internal networks, it can be public facing
- Easy to use email templating using go html/template
- Easy to use email templating using go html/template with tenant-specific customization
- Supports smtp configuration
- Sends out emails for account verification, forgot passwords, and magic links
- Supports passwordless authentication via magic links
- Supports password authentication
- Account lockout protection after failed authentication attempts (configurable)
- TODO: Supports third party authentication via Google (more to come)
- Uses token acknowledgement to prevent replay attacks and supports multiple devices
- TODO: Account management and administration via admin service
Expand All @@ -57,19 +59,73 @@ confidential values should use proper secrets management.
| WEBSITE_NAME | The name of the website the service will be used for | string | Latebit | Yes |
| VERIFICATION_URL | The url of your application that will make the token verification call | string | https://localhost:3000/verify | Yes |
| FORGOT_PASSWORD_URL | The url of your application that will use the forgot password call | string | https://localhost:3000/reset-password | Yes |
| MAGIC_LINK_URL | The url of your application that will submit the magic code call | string | https://localhost:3000/magic-link | Yes |
| MAGIC_URL | The url of your application that will submit the magic code call | string | https://localhost:3000/magic-link | Yes |
| MAGIC_CODE_EXPIRE_IN_MINUTES | The number of minutes the magic code will be valid for | int | 10 | Yes |
| EMAIL_SMTP | Whether or not to use smtp for sending emails | bool | true | Yes |
| EMAIL_SMTP_HOST | The smtp host to use for sending emails | string | localhost | Yes |
| EMAIL_SMTP_PORT | The smtp port to use for sending emails | int | 1025 | Yes |
| EMAIL_SMTP_USER | The smtp user to use for sending emails | string | user | Yes |
| EMAIL_SMTP_PASS | The smtp pass to use for sending emails | string | pass | Yes |
| EMAIL_SMTP_SECURE | Whether or not to use secure smtp for sending emails | bool | false | Yes |
| EMAIL_TEMPLATE_DIR | The directory where the email templates are located | string | src/bulwark-auth/email-templates | Yes |
| EMAIL_SEND_ADDRESS | The email address to send emails from | string | admin@latebit.io | Yes |
| GOOGLE_CLIENT_ID | The google client id to use for google authentication | string | secret.apps.googleusercontent.com | No | | |
| SERVICE_MODE | The service mode to run in only used for CI and tests | string | test | No |
| EMAIL_TEMPLATE_DIRS | The directory where the email templates are located | string | src/bulwark-auth/email-templates | No |
| EMAIL_FROM_ADDRESS | The email address to send emails from | string | admin@latebit.io | Yes |
| GOOGLE_CLIENT_ID | The google client id to use for google authentication | string | secret.apps.googleusercontent.com | No |
| LOCKOUT_DURATION_IN_SEC | Duration in seconds for account lockout after failed attempts | int | 300 | No |
| MAX_FAILED_ATTEMPTS | Maximum failed authentication attempts before lockout | int | 5 | No |
| ACCESS_TOKEN_EXPIRE_IN_SECONDS | Access token expiration time in seconds | int | 3600 | No |
| REFRESH_TOKEN_EXPIRE_IN_SECONDS | Refresh token expiration time in seconds | int | 86400 | No |
| TEST_MODE | Run in test mode (bypasses email sending) | bool | false | No |
| API_KEY | API key for securing endpoints (when API_KEY_ENABLE=true) | string | your-secure-api-key | No |
| API_KEY_ENABLE | Enable API key authentication | bool | false | No |
| CORS_ENABLED | Enable CORS support | bool | false | No |
| ALLOWED_WEB_ORIGINS | Comma-separated list of allowed CORS origins | string | http://localhost:3000 | No |

## Multi-Tenant Support

BulwarkAuth supports multi-tenancy out of the box, allowing you to isolate users, accounts, and authentication data by tenant ID.

### How It Works

- Each API request includes a `tenantId` parameter (or uses `"default"` for single-tenant setups)
- Accounts, tokens, signing keys, and authentication data are isolated per tenant
- Each tenant can have its own:
- JWT signing keys (automatically generated and rotated)
- Email templates
- Account lockout settings
- Token expiration policies

### Using Multi-Tenancy

When using the [bulwark-auth-guard](https://github.com/latebit-io/bulwark-auth-guard) client library, simply pass the tenant ID to all API calls:

```go
// Create account for a specific tenant
err := guard.Account.Create(ctx, "tenant-123", email, password)

// Authenticate user within their tenant
auth, err := guard.Authenticate.Password(ctx, "tenant-123", email, password, clientID)

// Validate token (automatically scoped to tenant)
claims, err := guard.Authenticate.ValidateAccessToken(ctx, "tenant-123", accessToken)
```

### Single-Tenant Setup

If you're running a single-tenant application, use `"default"` as your tenant ID:

```go
const tenantID = "default"

err := guard.Account.Create(ctx, tenantID, email, password)
```

### Benefits

- **Data Isolation**: Complete separation of user data between tenants
- **Security**: Tokens from one tenant cannot be used in another
- **Scalability**: Run multiple applications/customers on the same BulwarkAuth instance
- **Per-Tenant Configuration**: Customize settings for each tenant via email templates and future admin features

## Domain
For domain verification you will need access to your DNS provider to add an TXT entry to verify against
This key will need to verified before using this feature until then it will be ignored
Expand Down
Loading
Loading