maya-voice-agent / src /token_generator.py
rudyByte
deploy: flattened structure for Hugging Face
4cf98c9
"""
Generates Twilio Access Tokens for the CallSaathi Demo Caller Android app.
Security model:
- Uses API Key (SK...) + API Secret — NOT the Auth Token
- Tokens are short-lived (configurable, default 1 hour)
- Each token is scoped to only outgoing calls via TwiML App
- Tokens do NOT expose account credentials
Usage:
from token_generator import create_demo_caller_token
token_jwt = create_demo_caller_token()
"""
import os
import time
from twilio.jwt.access_token import AccessToken
from twilio.jwt.access_token.grants import VoiceGrant
from dotenv import load_dotenv
load_dotenv()
def create_demo_caller_token(identity: str = "demo-caller", ttl_seconds: int = 3600) -> str:
"""
Creates a Twilio Access Token for the demo caller Android app.
Args:
identity: Unique identifier for this client (default: "demo-caller")
ttl_seconds: Token lifetime in seconds (default: 3600 = 1 hour)
Returns:
JWT string to pass to the Android app's Twilio Voice SDK
Raises:
EnvironmentError: If required environment variables are missing
"""
account_sid = os.getenv("TWILIO_ACCOUNT_SID")
api_key_sid = os.getenv("TWILIO_API_KEY_SID")
api_key_secret = os.getenv("TWILIO_API_KEY_SECRET")
twiml_app_sid = os.getenv("TWILIO_TWIML_APP_SID")
# Validate all required env vars are present
missing = []
if not account_sid: missing.append("TWILIO_ACCOUNT_SID")
if not api_key_sid: missing.append("TWILIO_API_KEY_SID")
if not api_key_secret: missing.append("TWILIO_API_KEY_SECRET")
if not twiml_app_sid: missing.append("TWILIO_TWIML_APP_SID")
if missing:
raise EnvironmentError(
f"Missing required environment variables: {', '.join(missing)}\n"
"Run: python scripts/verify_twilio_config.py to check your .env file."
)
# Create the Access Token
token = AccessToken(
account_sid,
api_key_sid,
api_key_secret,
identity=identity,
ttl=ttl_seconds
)
# Add Voice Grant — allows outgoing calls via the TwiML App
voice_grant = VoiceGrant(
outgoing_application_sid=twiml_app_sid,
incoming_allow=False # Demo caller only makes calls, does not receive
)
token.add_grant(voice_grant)
jwt_string = token.to_jwt()
# Python 3.10+ friendly time formatting
expiry_time = time.strftime(
'%Y-%m-%d %H:%M:%S UTC',
time.gmtime(time.time() + ttl_seconds)
)
print(f"[TokenGen] Token created for '{identity}', expires: {expiry_time}")
return jwt_string
def create_demo_caller_token_response() -> dict:
"""
Returns a dict ready to be returned as a FastAPI JSON response.
"""
try:
token = create_demo_caller_token()
return {
"token": token,
"identity": "demo-caller",
"expires_in": 3600,
"status": "ok"
}
except EnvironmentError as e:
return {
"token": None,
"status": "error",
"message": str(e)
}
if __name__ == "__main__":
try:
print("\n--- TWILIO TOKEN VERIFICATION ---")
token = create_demo_caller_token()
print("\n✅ SUCCESS: Generated valid JWT token.")
print(f"Token (First 20 chars): {token[:20]}...")
print("\nIf you are seeing this, your .env keys are CORRECT.")
print("Now copy these keys to your Hugging Face Secrets.")
except Exception as e:
print(f"\n❌ ERROR: {str(e)}")