import base64
import hashlib
import secrets
from supabase.client import Client, ClientOptions, create_client
from werkzeug.local import LocalProxy
from flask import g, session, current_app
[docs]
def get_session_storage():
from app import FlaskSessionStorage
return FlaskSessionStorage()
[docs]
def get_db() -> Client:
if "db" not in g:
g.db = Client(
current_app.config["SUPABASE_URL"],
current_app.config["SUPABASE_KEY"],
options=ClientOptions(
storage=get_session_storage(),
flow_type="pkce"
),
)
return g.db
[docs]
def get_service_client() -> Client:
return create_client(
current_app.config["SUPABASE_URL"],
current_app.config["SUPABASE_SERVICE_KEY"],
options=ClientOptions(
auto_refresh_token=False,
persist_session=False,
)
)
client: Client = LocalProxy(get_db)
[docs]
def generate_code_verifier():
"""Generate a secure random code verifier (43-128 characters)."""
return secrets.token_urlsafe(64) # Secure random 64-character string
[docs]
def generate_code_challenge(verifier):
"""Create a SHA256 challenge from the code verifier (RFC 7636)."""
sha256_hash = hashlib.sha256(verifier.encode()).digest()
challenge = base64.urlsafe_b64encode(sha256_hash).decode().rstrip("=") # Remove '=' padding
return challenge