From add4eddd59106b3bacbaeffbec0e3b096c7b2857 Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Tue, 20 Aug 2024 23:17:45 +0000 Subject: [PATCH] feat: add third-party auth support --- supabase/_async/client.py | 34 ++++++++++++++++++++-------------- supabase/_sync/client.py | 34 ++++++++++++++++++++-------------- supabase/lib/client_options.py | 4 ++++ supabase/utils.py | 16 ++++++++++++++++ 4 files changed, 60 insertions(+), 28 deletions(-) create mode 100644 supabase/utils.py diff --git a/supabase/_async/client.py b/supabase/_async/client.py index 226b989e..5819807c 100644 --- a/supabase/_async/client.py +++ b/supabase/_async/client.py @@ -16,16 +16,10 @@ from supafunc import AsyncFunctionsClient from ..lib.client_options import ClientOptions +from ..utils import AuthProxy, SupabaseException from .auth_client import AsyncSupabaseAuthClient -# Create an exception class when user does not provide a valid url or key. -class SupabaseException(Exception): - def __init__(self, message: str): - self.message = message - super().__init__(self.message) - - class AsyncClient: """Supabase client class.""" @@ -77,10 +71,15 @@ def __init__( self.functions_url = f"{supabase_url}/functions/v1" # Instantiate clients. - self.auth = self._init_supabase_auth_client( - auth_url=self.auth_url, - client_options=options, - ) + if not options.access_token: + self.auth = self._init_supabase_auth_client( + auth_url=self.auth_url, + client_options=options, + ) + else: + self.access_token = options.access_token + self.auth = AuthProxy() + self.realtime = self._init_realtime_client( realtime_url=self.realtime_url, supabase_key=self.supabase_key, @@ -89,7 +88,9 @@ def __init__( self._postgrest = None self._storage = None self._functions = None - self.auth.on_auth_state_change(self._listen_to_auth_events) + + if not options.access_token: + self.auth.on_auth_state_change(self._listen_to_auth_events) @classmethod async def create( @@ -103,8 +104,13 @@ async def create( if auth_header is None: try: - session = await client.auth.get_session() - session_access_token = client._create_auth_header(session.access_token) + if not options.access_token: + session = await client.auth.get_session() + session_access_token = client._create_auth_header( + session.access_token + ) + else: + session_access_token = options.access_token except Exception as err: session_access_token = None diff --git a/supabase/_sync/client.py b/supabase/_sync/client.py index 47762630..2ac7b68f 100644 --- a/supabase/_sync/client.py +++ b/supabase/_sync/client.py @@ -16,16 +16,10 @@ from supafunc import SyncFunctionsClient from ..lib.client_options import ClientOptions +from ..utils import AuthProxy, SupabaseException from .auth_client import SyncSupabaseAuthClient -# Create an exception class when user does not provide a valid url or key. -class SupabaseException(Exception): - def __init__(self, message: str): - self.message = message - super().__init__(self.message) - - class SyncClient: """Supabase client class.""" @@ -77,10 +71,15 @@ def __init__( self.functions_url = f"{supabase_url}/functions/v1" # Instantiate clients. - self.auth = self._init_supabase_auth_client( - auth_url=self.auth_url, - client_options=options, - ) + if not options.access_token: + self.auth = self._init_supabase_auth_client( + auth_url=self.auth_url, + client_options=options, + ) + else: + self.access_token = options.access_token + self.auth = AuthProxy() + self.realtime = self._init_realtime_client( realtime_url=self.realtime_url, supabase_key=self.supabase_key, @@ -89,7 +88,9 @@ def __init__( self._postgrest = None self._storage = None self._functions = None - self.auth.on_auth_state_change(self._listen_to_auth_events) + + if not options.access_token: + self.auth.on_auth_state_change(self._listen_to_auth_events) @classmethod def create( @@ -103,8 +104,13 @@ def create( if auth_header is None: try: - session = client.auth.get_session() - session_access_token = client._create_auth_header(session.access_token) + if not options.access_token: + session = client.auth.get_session() + session_access_token = client._create_auth_header( + session.access_token + ) + else: + session_access_token = options.access_token except Exception as err: session_access_token = None diff --git a/supabase/lib/client_options.py b/supabase/lib/client_options.py index 4ff86589..c30ce494 100644 --- a/supabase/lib/client_options.py +++ b/supabase/lib/client_options.py @@ -51,6 +51,8 @@ class ClientOptions: flow_type: AuthFlowType = "implicit" """flow type to use for authentication""" + access_token: Union[str, None] = None + def replace( self, schema: Optional[str] = None, @@ -66,6 +68,7 @@ def replace( int, float, Timeout ] = DEFAULT_STORAGE_CLIENT_TIMEOUT, flow_type: Optional[AuthFlowType] = None, + access_token: Union[str, None] = None, ) -> "ClientOptions": """Create a new SupabaseClientOptions with changes""" client_options = ClientOptions() @@ -84,4 +87,5 @@ def replace( storage_client_timeout or self.storage_client_timeout ) client_options.flow_type = flow_type or self.flow_type + client_options.access_token = access_token or self.access_token return client_options diff --git a/supabase/utils.py b/supabase/utils.py new file mode 100644 index 00000000..7d8d4dd2 --- /dev/null +++ b/supabase/utils.py @@ -0,0 +1,16 @@ +from gotrue.errors import AuthError + + +# Create an exception class when user does not provide a valid url or key. +class SupabaseException(Exception): + def __init__(self, message: str): + self.message = message + super().__init__(self.message) + + +class AuthProxy: + def __getattr__(self, attr): + raise AuthError( + f"Supabase Client is configured with the access_token option, accessing supabase.auth.{attr} is not possible.", + None, + )