Module supertokens_python.recipe.thirdparty
Expand source code
# Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.
#
# This software is licensed under the Apache License, Version 2.0 (the
# "License") as published by the Apache Software Foundation.
#
# You may not use this file except in compliance with the License. You may
# obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import annotations
from typing import TYPE_CHECKING, Optional, Union
from .provider import ProviderClientConfig, ProviderConfig, ProviderInput
from .recipe import ThirdPartyRecipe
from .utils import InputOverrideConfig, SignInAndUpFeature, ThirdPartyOverrideConfig
if TYPE_CHECKING:
from supertokens_python.supertokens import RecipeInit
def init(
sign_in_and_up_feature: Optional[SignInAndUpFeature] = None,
override: Union[ThirdPartyOverrideConfig, None] = None,
) -> RecipeInit:
if sign_in_and_up_feature is None:
sign_in_and_up_feature = SignInAndUpFeature()
return ThirdPartyRecipe.init(sign_in_and_up_feature, override)
__all__ = [
"InputOverrideConfig", # deprecated, use `ThirdPartyOverrideConfig` instead
"ProviderClientConfig",
"ProviderConfig",
"ProviderInput",
"SignInAndUpFeature",
"ThirdPartyOverrideConfig",
"ThirdPartyRecipe",
"init",
]
Sub-modules
supertokens_python.recipe.thirdparty.apisupertokens_python.recipe.thirdparty.asynciosupertokens_python.recipe.thirdparty.constantssupertokens_python.recipe.thirdparty.exceptionssupertokens_python.recipe.thirdparty.interfacessupertokens_python.recipe.thirdparty.providersupertokens_python.recipe.thirdparty.providerssupertokens_python.recipe.thirdparty.recipesupertokens_python.recipe.thirdparty.recipe_implementationsupertokens_python.recipe.thirdparty.synciosupertokens_python.recipe.thirdparty.typessupertokens_python.recipe.thirdparty.utils
Functions
def init(sign_in_and_up_feature: Optional[SignInAndUpFeature] = None, override: Union[BaseOverrideConfig[RecipeInterface, APIInterface], None] = None)
Classes
class InputOverrideConfig (**data: Any)-
Base class for input override config with API overrides.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- BaseOverrideConfig
- BaseOverrideConfigWithoutAPI
- CamelCaseBaseModel
- APIResponse
- abc.ABC
- pydantic.main.BaseModel
- typing.Generic
Class variables
var model_config-
The type of the None singleton.
class ThirdPartyOverrideConfig (**data: Any)-
Base class for input override config with API overrides.
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.Ancestors
- BaseOverrideConfig
- BaseOverrideConfigWithoutAPI
- CamelCaseBaseModel
- APIResponse
- abc.ABC
- pydantic.main.BaseModel
- typing.Generic
Inherited members
class ProviderClientConfig (client_id: str, client_secret: Optional[str] = None, client_type: Optional[str] = None, scope: Optional[List[str]] = None, force_pkce: Optional[bool] = None, additional_config: Optional[Dict[str, Any]] = None)-
Expand source code
class ProviderClientConfig: def __init__( self, client_id: str, client_secret: Optional[str] = None, client_type: Optional[str] = None, scope: Optional[List[str]] = None, force_pkce: Optional[bool] = None, additional_config: Optional[Dict[str, Any]] = None, ): self.client_id = client_id self.client_secret = client_secret self.client_type = client_type self.scope = scope self.force_pkce = force_pkce self.additional_config = additional_config def to_json(self) -> Dict[str, Any]: res = { "clientId": self.client_id, "clientSecret": self.client_secret, "clientType": self.client_type, "scope": self.scope, "forcePKCE": self.force_pkce, "additionalConfig": self.additional_config, } return {k: v for k, v in res.items() if v is not None} @staticmethod def from_json(json: Dict[str, Any]) -> ProviderClientConfig: return ProviderClientConfig( client_id=json.get("clientId", ""), client_secret=json.get("clientSecret", None), client_type=json.get("clientType", None), scope=json.get("scope", None), force_pkce=json.get("forcePKCE", None), additional_config=json.get("additionalConfig", None), )Subclasses
Static methods
def from_json(json: Dict[str, Any]) ‑> ProviderClientConfig
Methods
def to_json(self) ‑> Dict[str, Any]
class ProviderConfig (third_party_id: str, name: Optional[str] = None, clients: Optional[List[ProviderClientConfig]] = None, authorization_endpoint: Optional[str] = None, authorization_endpoint_query_params: Optional[Dict[str, Union[str, None]]] = None, token_endpoint: Optional[str] = None, token_endpoint_body_params: Optional[Dict[str, Union[str, None]]] = None, user_info_endpoint: Optional[str] = None, user_info_endpoint_query_params: Optional[Dict[str, Union[str, None]]] = None, user_info_endpoint_headers: Optional[Dict[str, Union[str, None]]] = None, jwks_uri: Optional[str] = None, oidc_discovery_endpoint: Optional[str] = None, user_info_map: Optional[UserInfoMap] = None, require_email: Optional[bool] = None, validate_id_token_payload: Optional[Callable[[Dict[str, Any], ProviderConfigForClient, Dict[str, Any]], Awaitable[None]]] = None, generate_fake_email: Optional[Callable[[str, str, Dict[str, Any]], Awaitable[str]]] = None, validate_access_token: Optional[Callable[[str, ProviderConfigForClient, Dict[str, Any]], Awaitable[None]]] = None)-
Expand source code
class ProviderConfig(CommonProviderConfig): def __init__( self, third_party_id: str, name: Optional[str] = None, clients: Optional[List[ProviderClientConfig]] = None, authorization_endpoint: Optional[str] = None, authorization_endpoint_query_params: Optional[ Dict[str, Union[str, None]] ] = None, token_endpoint: Optional[str] = None, token_endpoint_body_params: Optional[Dict[str, Union[str, None]]] = None, user_info_endpoint: Optional[str] = None, user_info_endpoint_query_params: Optional[Dict[str, Union[str, None]]] = None, user_info_endpoint_headers: Optional[Dict[str, Union[str, None]]] = None, jwks_uri: Optional[str] = None, oidc_discovery_endpoint: Optional[str] = None, user_info_map: Optional[UserInfoMap] = None, require_email: Optional[bool] = None, validate_id_token_payload: Optional[ Callable[ [Dict[str, Any], ProviderConfigForClient, Dict[str, Any]], Awaitable[None], ] ] = None, generate_fake_email: Optional[ Callable[[str, str, Dict[str, Any]], Awaitable[str]] ] = None, validate_access_token: Optional[ Callable[ [str, ProviderConfigForClient, Dict[str, Any]], Awaitable[None], ] ] = None, ): super().__init__( third_party_id, name, authorization_endpoint, authorization_endpoint_query_params, token_endpoint, token_endpoint_body_params, user_info_endpoint, user_info_endpoint_query_params, user_info_endpoint_headers, jwks_uri, oidc_discovery_endpoint, user_info_map, require_email, validate_id_token_payload, generate_fake_email, validate_access_token, ) self.clients = clients def to_json(self) -> Dict[str, Any]: d = CommonProviderConfig.to_json(self) if self.clients is not None: d["clients"] = [c.to_json() for c in self.clients] return d @staticmethod def from_json(json: Dict[str, Any]) -> ProviderConfig: return ProviderConfig( third_party_id=json.get("thirdPartyId", ""), name=json.get("name", None), clients=[ ProviderClientConfig.from_json(c) for c in json.get("clients", []) ], authorization_endpoint=json.get("authorizationEndpoint", None), authorization_endpoint_query_params=json.get( "authorizationEndpointQueryParams", None ), token_endpoint=json.get("tokenEndpoint", None), token_endpoint_body_params=json.get("tokenEndpointBodyParams", None), user_info_endpoint=json.get("userInfoEndpoint", None), user_info_endpoint_query_params=json.get( "userInfoEndpointQueryParams", None ), user_info_endpoint_headers=json.get("userInfoEndpointHeaders", None), jwks_uri=json.get("jwksURI", None), oidc_discovery_endpoint=json.get("oidcDiscoveryEndpoint", None), user_info_map=UserInfoMap.from_json(json.get("userInfoMap", None)), require_email=json.get("requireEmail", None), validate_id_token_payload=None, generate_fake_email=None, validate_access_token=None, )Ancestors
Static methods
def from_json(json: Dict[str, Any]) ‑> ProviderConfig
Methods
def to_json(self) ‑> Dict[str, Any]
class ProviderInput (config: ProviderConfig, include_in_non_public_tenants_by_default: bool = False, override: Optional[Callable[[Provider], Provider]] = None)-
Expand source code
class ProviderInput: def __init__( self, config: ProviderConfig, include_in_non_public_tenants_by_default: bool = False, override: Optional[Callable[[Provider], Provider]] = None, ): self.config = config self.include_in_non_public_tenants_by_default = ( include_in_non_public_tenants_by_default ) self.override = override class SignInAndUpFeature (providers: Optional[List[ProviderInput]] = None)-
Expand source code
class SignInAndUpFeature: def __init__(self, providers: Optional[List[ProviderInput]] = None): if providers is None: providers = [] third_party_id_set: Set[str] = set() for provider in providers: third_party_id = provider.config.third_party_id if third_party_id in third_party_id_set: raise_bad_input_exception( "The providers array has multiple entries for the same third party provider." ) third_party_id_set.add(third_party_id) self.providers = providers class ThirdPartyRecipe (recipe_id: str, app_info: AppInfo, config: ThirdPartyConfig, _ingredients: ThirdPartyIngredients)-
Helper class that provides a standard way to create an ABC using inheritance.
Expand source code
class ThirdPartyRecipe(RecipeModule): recipe_id = "thirdparty" __instance = None def __init__( self, recipe_id: str, app_info: AppInfo, config: ThirdPartyConfig, _ingredients: ThirdPartyIngredients, ): super().__init__(recipe_id, app_info) self.config = validate_and_normalise_user_input(config=config) self.providers = self.config.sign_in_and_up_feature.providers recipe_implementation = RecipeImplementation( Querier.get_instance(recipe_id), self.providers ) self.recipe_implementation: RecipeInterface = self.config.override.functions( recipe_implementation ) api_implementation = APIImplementation() self.api_implementation: APIInterface = self.config.override.apis( api_implementation ) def callback(): mt_recipe = MultitenancyRecipe.get_instance_optional() if mt_recipe: mt_recipe.static_third_party_providers = self.providers mt_recipe.all_available_first_factors.append("thirdparty") PostSTInitCallbacks.add_post_init_callback(callback) def is_error_from_this_recipe_based_on_instance(self, err: Exception) -> bool: return isinstance(err, SuperTokensError) and ( isinstance(err, SuperTokensThirdPartyError) ) def get_apis_handled(self) -> List[APIHandled]: return [ APIHandled( NormalisedURLPath(SIGNINUP), "post", SIGNINUP, self.api_implementation.disable_sign_in_up_post, ), APIHandled( NormalisedURLPath(AUTHORISATIONURL), "get", AUTHORISATIONURL, self.api_implementation.disable_authorisation_url_get, ), APIHandled( NormalisedURLPath(APPLE_REDIRECT_HANDLER), "post", APPLE_REDIRECT_HANDLER, self.api_implementation.disable_apple_redirect_handler_post, ), ] async def handle_api_request( self, request_id: str, tenant_id: str, request: BaseRequest, path: NormalisedURLPath, method: str, response: BaseResponse, user_context: Dict[str, Any], ): api_options = APIOptions( request, response, self.recipe_id, self.config, self.recipe_implementation, self.providers, self.app_info, ) if request_id == SIGNINUP: return await handle_sign_in_up_api( self.api_implementation, tenant_id, api_options, user_context ) if request_id == AUTHORISATIONURL: return await handle_authorisation_url_api( self.api_implementation, tenant_id, api_options, user_context ) if request_id == APPLE_REDIRECT_HANDLER: return await handle_apple_redirect_api( self.api_implementation, api_options, user_context ) return None async def handle_error( self, request: BaseRequest, err: SuperTokensError, response: BaseResponse, user_context: Dict[str, Any], ) -> BaseResponse: # type: ignore if isinstance(err, SuperTokensThirdPartyError): raise err def get_all_cors_headers(self) -> List[str]: return [] @staticmethod def init( sign_in_and_up_feature: SignInAndUpFeature, override: Union[ThirdPartyOverrideConfig, None] = None, ): from supertokens_python.plugins import OverrideMap, apply_plugins config = ThirdPartyConfig( sign_in_and_up_feature=sign_in_and_up_feature, override=override, ) def func(app_info: AppInfo, plugins: List[OverrideMap]): if ThirdPartyRecipe.__instance is None: ingredients = ThirdPartyIngredients() ThirdPartyRecipe.__instance = ThirdPartyRecipe( recipe_id=ThirdPartyRecipe.recipe_id, app_info=app_info, _ingredients=ingredients, config=apply_plugins( recipe_id=ThirdPartyRecipe.recipe_id, config=config, plugins=plugins, ), ) return ThirdPartyRecipe.__instance raise_general_exception( "ThirdParty recipe has already been initialised. Please check your code for bugs." ) return func @staticmethod def get_instance() -> ThirdPartyRecipe: if ThirdPartyRecipe.__instance is not None: return ThirdPartyRecipe.__instance raise_general_exception( "Initialisation not done. Did you forget to call the SuperTokens.init function?" ) @staticmethod def reset(): if ("SUPERTOKENS_ENV" not in environ) or ( environ["SUPERTOKENS_ENV"] != "testing" ): raise_general_exception("calling testing function in non testing env") ThirdPartyRecipe.__instance = None # instance functions below...............Ancestors
- RecipeModule
- abc.ABC
Class variables
var recipe_id-
The type of the None singleton.
Static methods
def get_instance() ‑> ThirdPartyRecipedef init(sign_in_and_up_feature: SignInAndUpFeature, override: Union[BaseOverrideConfig[RecipeInterface, APIInterface], None] = None)def reset()
Methods
def get_all_cors_headers(self) ‑> List[str]def get_apis_handled(self) ‑> List[APIHandled]async def handle_api_request(self, request_id: str, tenant_id: str, request: BaseRequest, path: NormalisedURLPath, method: str, response: BaseResponse, user_context: Dict[str, Any])async def handle_error(self, request: BaseRequest, err: SuperTokensError, response: BaseResponse, user_context: Dict[str, Any])def is_error_from_this_recipe_based_on_instance(self, err: Exception) ‑> bool
Inherited members