Conversation
Create Ent schema for authentication tokens with: - UUID primary key - Unique name for human-readable identification - SHA-256 token hash for secure storage - Optional description field - Expiration timestamp Indexes on name and token_hash for efficient lookups during authentication validation. Co-authored-by: construct-agent <noreply@construct.sh>
Create Identity and Transport context utilities for request authentication flow: - Identity: carries authenticated subject, auth method, admin status - AuthMethod enum: unix_socket, token, or unspecified - Transport context: tracks connection type (unix vs tcp) Context helpers use unexported key types to prevent collisions. Co-authored-by: construct-agent <noreply@construct.sh>
Add TokenProvider with: - Secure token generation using crypto/rand (32 bytes) - SHA-256 hashing for token storage - Token format validation (ct_ prefix + base64url) - Setup code generation (8-char alphanumeric, XXXX-XXXX format) - In-memory setup code storage with expiration - Thread-safe code consumption (single-use with mutex) Setup codes exclude ambiguous characters (0/O, 1/I) and are case-insensitive for user convenience. Co-authored-by: construct-agent <noreply@construct.sh>
Implement unary and streaming interceptors that: - Allow unauthenticated access to ExchangeSetupCode - Grant admin privileges to Unix socket connections - Validate Bearer tokens for TCP connections - Hash and lookup tokens in database - Check token expiration - Populate Identity context for downstream handlers Returns CodeUnauthenticated for auth failures, CodeInternal for unexpected errors. Co-authored-by: construct-agent <noreply@construct.sh>
Extract authentication logic into shared authenticate() method to reduce duplication between unary and streaming interceptors. Rename methods to WrapUnary and WrapStreamingHandler to match ConnectRPC interceptor interface conventions. Co-authored-by: construct-agent <noreply@construct.sh>
Add handler for all auth operations: - CreateToken: generates secure tokens with configurable expiry - CreateSetupCode: creates short-lived exchange codes - ListTokens: queries tokens with optional filters - RevokeToken: deletes tokens by ID - ExchangeSetupCode: unauthenticated bootstrap endpoint All admin-only operations check Identity.IsAdmin from context. ExchangeSetupCode validates uniqueness before token creation. Proper error codes for permission, validation, and not found cases. Co-authored-by: construct-agent <noreply@construct.sh>
Wire up authentication system: - Create TokenProvider singleton in NewServer - Add transport context injection via ConnContext (unix vs tcp) - Create AuthInterceptor and apply to all handlers - Register AuthServiceHandler with interceptor - Pass TokenProvider through HandlerOptions All service handlers now protected by authentication middleware. Unix socket connections automatically granted admin privileges. Co-authored-by: construct-agent <noreply@construct.sh>
Unit tests for TokenProvider: - Token generation with proper format and uniqueness - Consistent token hashing - Token format validation - Setup code creation with correct format - Setup code consumption (single-use, case-insensitive) - Setup code expiration Integration tests for AuthService: - CreateToken with validation and duplicate detection - CreateSetupCode generation - ListTokens with filters and expiry handling - RevokeToken by ID with proper error handling - ExchangeSetupCode validation Update test infrastructure to include TokenProvider and Token table cleanup between test runs. Co-authored-by: construct-agent <noreply@construct.sh>
Add WrapStreamingClient to AuthInterceptor to fully implement connect.Interceptor interface. Add Auth() method to Client for accessing AuthService operations. Include auth field in Client struct and wire up AuthServiceClient in NewClient and mock implementations. Generate mockgen mock for AuthServiceClient to support testing. Fix test compilation by properly escaping quotes in error messages. Co-authored-by: construct-agent <noreply@construct.sh>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This PR implements a comprehensive token-based authentication system for Construct, enabling secure remote daemon access while maintaining backward compatibility with local Unix socket connections.
Architecture
Transport-Based Trust Model
Authentication is determined by connection transport:
Key Components
Token Provider
Auth Interceptor
ExchangeSetupCodefor unauthenticated bootstrapAuthService RPCs
CreateToken: Generate new API tokens (admin only)CreateSetupCode: Generate short-lived exchange codes (admin only)ListTokens: Query tokens with filters (admin only)RevokeToken: Delete tokens by ID (admin only)ExchangeSetupCode: Bootstrap authentication without credentials (unauthenticated)Database Schema
New
Tokenentity with Ent:id: UUID primary keyname: Unique human-readable identifiertype: Enum (api_token | setup_code)token_hash: SHA-256 hash for validationdescription: Optional metadataexpires_at: Expiration timestampcreated_at/updated_at: Automatic timestampsIndexes on
nameandtoken_hashfor efficient lookups.Security Features
✅ Cryptographically secure token generation (crypto/rand)
✅ Only SHA-256 hashes stored in database
✅ Plaintext tokens shown once at creation
✅ Configurable token expiration (default 90 days, max 365 days)
✅ Setup codes expire quickly (default 20 minutes, max 72 hours)
✅ Single-use setup codes (deleted after consumption)
✅ Case-insensitive setup codes for usability
✅ Thread-safe setup code storage with mutex
✅ Admin-only token management operations
Setup Code Flow
Designed for secure token distribution without exposing tokens:
construct daemon token create --setup-code laptopvia Unix socketABCD-1234, stores in memory (20min TTL)construct context add prod --endpoint https://... --setup-code ABCD-1234ExchangeSetupCodeRPC (unauthenticated)Testing
Unit Tests (
backend/api/auth/token_test.go)Integration Tests (
backend/api/auth_test.go)Test Infrastructure Updates
All tests pass and compile successfully.
Changes
New Files
backend/memory/schema/token.go- Token entity definitionbackend/memory/schema/types/token.go- TokenType enumbackend/api/auth/identity.go- Identity and AuthMethod typesbackend/api/auth/transport.go- Transport context utilitiesbackend/api/auth/token.go- TokenProvider implementationbackend/api/auth/interceptor.go- Authentication interceptorbackend/api/auth.go- AuthService handlerbackend/api/auth/token_test.go- TokenProvider unit testsbackend/api/auth_test.go- AuthService integration testsapi/go/client/mocks/auth.connect_mock.go- Generated mockModified Files
backend/api/api.go- Integrated auth interceptor and transport contextbackend/api/api_test.go- Added TokenProvider and Token cleanupapi/go/client/client.go- Added Auth() methodGenerated Files
backend/memory/*- Ent-generated code for Token entityapi/go/v1/v1connect/auth.connect.go- ConnectRPC service handlers (already existed)Backward Compatibility
✅ Local Unix socket usage unchanged (no auth required)
✅ Existing commands continue to work without modification
✅ No breaking changes to API or CLI