File size: 3,573 Bytes
4cf98c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
"""
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)}")