@@ -130,6 +130,53 @@ class Config:
130130
131131# FLASK APPLICATION SETUP
132132
133+ from functools import wraps
134+ from flask import request , jsonify , g
135+ import jwt
136+ import os
137+
138+ def require_jwt_auth (f ):
139+ @wraps (f )
140+ def decorated (* args , ** kwargs ):
141+ auth_header = request .headers .get ("Authorization" )
142+
143+ if not auth_header or not auth_header .startswith ("Bearer " ):
144+ return jsonify ({
145+ "error" : "Unauthorized" ,
146+ "message" : "Authorization: Bearer <token> required"
147+ }), 401
148+
149+ token = auth_header .split (" " , 1 )[1 ]
150+
151+ try :
152+ payload = jwt .decode (
153+ token ,
154+ os .getenv ("JWT_SECRET_KEY" ),
155+ algorithms = ["HS256" ]
156+ )
157+
158+ if payload .get ("type" ) != "access" :
159+ return jsonify ({
160+ "error" : "Invalid token type"
161+ }), 401
162+
163+ # Attach user to request context
164+ g .user = {
165+ "user_id" : payload .get ("user_id" ),
166+ "tier" : payload .get ("tier" ),
167+ "metadata" : payload .get ("metadata" , {})
168+ }
169+
170+ except jwt .ExpiredSignatureError :
171+ return jsonify ({"error" : "Token expired" }), 401
172+ except jwt .InvalidTokenError :
173+ return jsonify ({"error" : "Invalid token" }), 401
174+
175+ return f (* args , ** kwargs )
176+
177+ return decorated
178+
179+
133180app = Flask (__name__ )
134181app .config ['SECRET_KEY' ] = Config .SECRET_KEY
135182app .config ['MAX_CONTENT_LENGTH' ] = Config .MAX_CONTENT_LENGTH
@@ -1010,6 +1057,40 @@ def allow_request(api_key: Optional[str]) -> Tuple[bool, Optional[Dict[str, Any]
10101057# =============================================================================
10111058
10121059import secrets
1060+ import secrets
1061+
1062+ @app .route ('/auth/api-key' , methods = ['POST' ])
1063+ @require_jwt_auth
1064+ def create_api_key ():
1065+ user_id = g .user ['user_id' ] # from JWT middleware
1066+
1067+ api_key = "rk_" + secrets .token_urlsafe (32 )
1068+ api_key_hash = SecurityUtils .hash_api_key (api_key )
1069+ api_key_prefix = SecurityUtils .get_api_key_prefix (api_key )
1070+
1071+ conn = db_pool .get_connection ()
1072+ cursor = conn .cursor ()
1073+
1074+ cursor .execute ("""
1075+ INSERT INTO users (
1076+ api_key_hash,
1077+ api_key_prefix,
1078+ tier,
1079+ request_count,
1080+ total_requests,
1081+ blocked
1082+ ) VALUES (?, ?, 'free', 0, 0, 0)
1083+ """ , (api_key_hash , api_key_prefix ))
1084+
1085+ conn .commit ()
1086+ db_pool .return_connection (conn )
1087+
1088+ return jsonify ({
1089+ "api_key" : api_key ,
1090+ "tier" : "free" ,
1091+ "note" : "Save this key now. It will not be shown again."
1092+ }), 201
1093+
10131094
10141095@app .route ('/auth/create_api_key' , methods = ['POST' ])
10151096def create_api_key ():
0 commit comments