5.2 KiB
5.2 KiB
Token Verification: App ID From Token vs Separate Parameter
Current Implementation Analysis
Current Flow (Requires app_id parameter):
1. Client: POST /api/verify {"token": "TESTT-abc123", "app_id": "test.example.com"}
2. System: Get app by app_id → Validate token against app's stored hashes
3. Result: Token validated within specific application scope
Proposed Alternative (Extract app_id from token):
1. Client: POST /api/verify {"token": "TESTT-abc123"}
2. System: Extract prefix "TEST" → Find app by token_prefix → Validate token
3. Result: Token validated without requiring app_id parameter
Security Analysis
✅ Advantages of Token-Only Verification:
1. Simpler API Usage
// Current (requires app knowledge)
await verify({token: "TESTT-abc123", app_id: "test.example.com"});
// Proposed (token-only)
await verify({token: "TESTT-abc123"});
2. Prevents App ID Mismatches
- Current: Client could provide wrong app_id (though validation would fail)
- Proposed: App is determined directly from token - no mismatch possible
3. Better Token Portability
- Tokens are self-describing and don't require external context
- Useful for tokens shared across different applications/services
❌ Security Risks of Token-Only Verification:
1. Information Disclosure Through Enumeration
# Attacker can discover applications by trying token prefixes
curl -X POST /api/verify -d '{"token": "TESTX-fakehash"}'
# Response reveals if "TEST" application exists
curl -X POST /api/verify -d '{"token": "PRODX-fakehash"}'
# Response reveals if "PROD" application exists
2. Reduced Access Control Granularity
Current: Client must know both token AND which app it belongs to
Proposed: Client only needs token - loses "need to know" app context
3. Prefix Collision Risk
-- Multiple apps could theoretically have same prefix
INSERT INTO applications (app_id, token_prefix) VALUES
('app1.com', 'TEST'),
('app2.com', 'TEST'); -- Collision!
4. Weaker Defense Against Token Leakage
- Current: Leaked token + need app_id knowledge = double barrier
- Proposed: Leaked token alone is sufficient = single barrier
Implementation Feasibility
Required Changes for Token-Only Verification:
// 1. Add repository method
func (r *ApplicationRepository) GetByTokenPrefix(ctx context.Context, prefix string) (*domain.Application, error)
// 2. Extract prefix from token
func extractTokenPrefix(token string) string {
dashIndex := strings.Index(token, "-")
if dashIndex >= 3 && dashIndex <= 6 {
return token[:dashIndex-1] // Remove "T" or "UT" part
}
return ""
}
// 3. Modified verification flow
func (s *tokenService) VerifyTokenOnly(ctx context.Context, token string) (*domain.VerifyResponse, error) {
prefix := extractTokenPrefix(token)
app, err := s.appRepo.GetByTokenPrefix(ctx, prefix)
if err != nil {
return &domain.VerifyResponse{Valid: false, Error: "Invalid token"}, nil
}
// Continue with existing verification logic...
}
Database Schema Considerations:
-- Ensure unique prefixes (recommended)
ALTER TABLE applications ADD CONSTRAINT unique_token_prefix
UNIQUE (token_prefix) WHERE token_prefix != '';
-- Index already exists from migration 003
-- CREATE INDEX idx_applications_token_prefix ON applications(token_prefix);
Recommendation: Keep Current Implementation (Require app_id)
Reasoning:
Security-First Approach 🛡️
- Prevents enumeration attacks - attackers can't discover apps by probing prefixes
- Maintains access control granularity - clients must know token + app context
- Defense in depth - two required pieces of information instead of one
- Clear audit trails - logs show which app context was used for verification
Architectural Benefits 🏗️
- Explicit application scoping - makes it clear which app owns the token
- Better error handling - can distinguish between "invalid app" vs "invalid token"
- Supports multi-tenancy - different apps can have isolated token validation
- Future extensibility - can add per-app validation rules without breaking changes
Operational Benefits 🔧
- Clear API contracts - consumers explicitly specify their context
- Better monitoring - can track usage per application
- Simpler debugging - logs clearly show app context for each verification
Optional: Provide Both Endpoints
// Existing secure endpoint (recommended for production)
POST /api/verify
{
"token": "TESTT-abc123",
"app_id": "test.example.com"
}
// Optional convenience endpoint (for development/testing)
POST /api/verify/token-only
{
"token": "TESTT-abc123"
}
Final Answer
Keep the current implementation requiring app_id for security and architectural reasons. The slight inconvenience of requiring the app_id parameter provides significant security benefits and maintains better system architecture.
The token prefix provides tampering protection (which is working correctly), but requiring separate app_id provides additional security layers that outweigh the convenience of token-only verification.