Authentication & Authorization
Security is critical for production AI agents. This article covers the authentication flow, token exchange patterns, and permission models used in our system.
Authentication Flow
sequenceDiagram
autonumber
participant U as User (Web / WhatsApp)
participant FE as Frontend (Next.js / Channel)
participant FA as Firebase Auth
participant SA as Support Agent
participant ADM as Firebase Admin SDK
participant MCP as MCP Servers
%% 1. User authenticates with Firebase
U->>FE: Sign in (email/password, OAuth, etc.)
FE->>FA: Auth request
FA-->>FE: Firebase ID token (user-firebase-token)
%% 2. Frontend calls Support Agent with user token
FE->>SA: POST /process (Authorization: Bearer user token)
SA->>FA: Verify ID token
FA-->>SA: Decoded token (uid, email, permissions)
%% 3. Support Agent generates service account token
SA->>ADM: Create custom token for service account
ADM-->>SA: Service account token (JWT)
Note right of SA: Cache in MCP_AUTH_TOKEN and\nrefresh before expiry
%% 4. Agent tools call MCP servers with service token
SA->>MCP: JSON-RPC 2.0 over HTTP\n(Authorization: Bearer service token)
%% 5. MCP servers validate service account token
MCP->>FA: Verify ID token (service account)
FA-->>MCP: Decoded token (issuer, claims)
Note right of MCP: Issuer ends with\n.iam.gserviceaccount.com\n→ treat as trusted service account
%% 6. MCP responds and agent replies to user
MCP-->>SA: JSON-RPC 2.0 response
SA-->>FE: HTTP 200 OK (response, conversation_id)
FE-->>U: Render agent reply
Token Types
User Firebase Token
Issuer: https://securetoken.google.com/{project-id}
Purpose: Authenticate end users
Scope: User-specific permissions
Lifetime: 1 hour (Firebase default)
Usage:
- Frontend sends with every request to Support Agent
- Support Agent validates using Firebase Admin SDK
- Contains user identity (UID, email) and custom claims
Service Account Token
Issuer: firebase-adminsdk-xxx@{project-id}.iam.gserviceaccount.com
Purpose: Service-to-service authentication
Scope: Full access to MCP services
Lifetime: 1 hour (auto-refreshed)
Usage:
- Generated by Support Agent using Firebase Admin SDK
- Used for all MCP server calls
- Cached in memory with thread-safe locking
- Auto-refreshes when expiring within 5 minutes
Token Management
Service Account Token Cache
The Support Agent implements intelligent token caching:
# Token refresh logic
refresh_needed = (
not token or
not expires_at or
expires_at <= (now + timedelta(minutes=5))
)
Features:
- Cached in memory with thread-safe locking
- Auto-refreshes when expiring within 5 minutes
- Stored in
MCP_AUTH_TOKENenvironment variable - Lifetime: 1 hour (3600 seconds)
Token Generation
from firebase_admin import auth
# Generate service account token
service_account_token = auth.create_custom_token(service_account_uid)
Permission Model
Format: {action}:{resource}
read:product-catalogue- Read product dataread:crm- Read customer datawrite:crm- Create/update customer data
Service Accounts
Service accounts are automatically granted all permissions. They’re identified by their issuer format:
- Pattern:
*.iam.gserviceaccount.com - Full access to all MCP services
- No permission checks required
User Permissions
User tokens require explicit permissions:
- Checked via custom claims in Firebase token
- Validated before allowing tool execution
- Can be restricted per user or role
Security Implementation
Token Validation
All tokens are validated using Firebase Admin SDK:
from firebase_admin import auth
# Validate user token
decoded_token = auth.verify_id_token(user_token)
user_id = decoded_token['uid']
email = decoded_token.get('email')
permissions = decoded_token.get('permissions', [])
Service Account Detection
MCP servers detect service account tokens by issuer format:
issuer = decoded_token.get('iss', '')
is_service_account = issuer.endswith('.iam.gserviceaccount.com')
if is_service_account:
# Grant full access
return True
else:
# Check user permissions
return check_user_permissions(decoded_token)
Permission Checks
Before executing tools, MCP servers verify permissions:
def check_permission(token, action, resource):
if is_service_account(token):
return True
required_permission = f"{action}:{resource}"
user_permissions = token.get('permissions', [])
return required_permission in user_permissions
Security Best Practices
1. Secrets Management
- Never commit secrets to git
- Use Secret Manager for all sensitive data
- Rotate secrets regularly
- Store service account keys in GCP Secret Manager
2. Token Validation
- Always validate Firebase tokens
- Check token expiration
- Verify issuer and audience
- Validate custom claims
3. Network Security
- Use HTTPS for all endpoints
- Configure CORS properly
- Use VPC connector for private services (optional)
- Implement rate limiting
4. Error Handling
- Don’t leak sensitive information in errors
- Log authentication failures
- Implement proper error codes
- Return generic error messages to clients
Environment Variables
Support Agent
FIREBASE_PROJECT_ID=<PROJECT_ID>
CATALOGUE_MCP_URL=https://mcp-product-catalogue-bd66ql2x7q-ts.a.run.app
CRM_MCP_URL=https://mcp-crm-bd66ql2x7q-ts.a.run.app
CORS_ORIGINS=https://<PROJECT_ID>.web.app,https://<PROJECT_ID>.firebaseapp.com
PORT=8000
DEBUG_HTTP=false
MCP Servers
FIREBASE_PROJECT_ID=<PROJECT_ID>
GOOGLE_CLOUD_PROJECT=<PROJECT_ID>
FIREBASE_SERVICE_ACCOUNT_PATH=/app/common/auth/firebase-service-account.json
PORT=8000
DEBUG_HTTP=false
Troubleshooting Authentication
Common Issues
- Token Expired
- Service account tokens auto-refresh
- Check
MCP_AUTH_TOKENis set in environment - Verify
FIREBASE_PROJECT_IDis configured
- Permission Denied
- Verify user has required permissions
- Check token includes permission claims
- Service accounts have full access by default
- Invalid Token
- Verify token format
- Check Firebase project ID matches
- Ensure token hasn’t been revoked
Next Steps
In the next article, we’ll explore the MCP Protocol Implementation, covering JSON-RPC 2.0 format, tool definitions, and communication patterns.