File size: 4,534 Bytes
22f818e | 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 113 114 115 116 117 118 119 120 | import aiohttp
from typing import Optional
from Backend.core.config import settings
from Backend.core.logging import get_logger
logger = get_logger(__name__)
class SupabaseAuthService:
def __init__(self):
self.url = settings.supabase_url
self.service_key = settings.supabase_key
self.headers = {
"apikey": self.service_key,
"Authorization": f"Bearer {self.service_key}",
"Content-Type": "application/json",
}
async def invite_user(self, email: str, redirect_to: Optional[str] = None) -> dict:
invite_url = f"{self.url}/auth/v1/invite"
payload = {
"email": email,
}
if redirect_to:
payload["options"] = {"redirectTo": redirect_to}
async with aiohttp.ClientSession() as session:
async with session.post(invite_url, json=payload, headers=self.headers) as response:
result = await response.json()
if response.status == 200:
logger.info(f"Invite sent to {email}")
return {
"success": True,
"message": f"Invitation email sent to {email}",
"user_id": result.get("id"),
"email": email,
}
else:
error_msg = result.get("msg") or result.get("message") or str(result)
logger.error(f"Failed to invite {email}: {error_msg}")
return {
"success": False,
"message": error_msg,
"email": email,
}
async def create_user(self, email: str, password: str, user_metadata: Optional[dict] = None) -> dict:
create_url = f"{self.url}/auth/v1/admin/users"
payload = {
"email": email,
"password": password,
"email_confirm": True,
}
if user_metadata:
payload["user_metadata"] = user_metadata
async with aiohttp.ClientSession() as session:
async with session.post(create_url, json=payload, headers=self.headers) as response:
result = await response.json()
if response.status in [200, 201]:
logger.info(f"User created: {email}")
return {
"success": True,
"user_id": result.get("id"),
"email": email,
}
else:
error_msg = result.get("msg") or result.get("message") or str(result)
return {
"success": False,
"message": error_msg,
}
async def send_magic_link(self, email: str, redirect_to: Optional[str] = None) -> dict:
magic_url = f"{self.url}/auth/v1/magiclink"
payload = {"email": email}
if redirect_to:
payload["options"] = {"redirectTo": redirect_to}
async with aiohttp.ClientSession() as session:
async with session.post(magic_url, json=payload, headers=self.headers) as response:
if response.status == 200:
return {
"success": True,
"message": f"Magic link sent to {email}",
}
else:
result = await response.json()
return {
"success": False,
"message": result.get("msg") or str(result),
}
async def get_user(self, user_id: str) -> Optional[dict]:
user_url = f"{self.url}/auth/v1/admin/users/{user_id}"
async with aiohttp.ClientSession() as session:
async with session.get(user_url, headers=self.headers) as response:
if response.status == 200:
return await response.json()
return None
async def delete_user(self, user_id: str) -> bool:
delete_url = f"{self.url}/auth/v1/admin/users/{user_id}"
async with aiohttp.ClientSession() as session:
async with session.delete(delete_url, headers=self.headers) as response:
return response.status == 200
supabase_auth = SupabaseAuthService()
|