Module supertokens_python.recipe.accountlinking.types

Expand source code
# Copyright (c) 2024, 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, Any, Awaitable, Callable, Dict, List, Optional, Union

from typing_extensions import Literal

from supertokens_python.recipe.accountlinking.interfaces import (
    RecipeInterface,
)
from supertokens_python.recipe.session import SessionContainer
from supertokens_python.types import (
    AccountInfo,
    LoginMethod,
    RecipeUserId,
    User,
)
from supertokens_python.types.config import (
    BaseConfigWithoutAPIOverride,
    BaseNormalisedConfigWithoutAPIOverride,
    BaseNormalisedOverrideConfigWithoutAPI,
    BaseOverrideableConfig,
    BaseOverrideConfigWithoutAPI,
)

if TYPE_CHECKING:
    from supertokens_python.recipe.thirdparty.types import ThirdPartyInfo
    from supertokens_python.recipe.webauthn.types.base import WebauthnInfo

AccountLinkingOverrideConfig = BaseOverrideConfigWithoutAPI[RecipeInterface]
NormalisedAccountLinkingOverrideConfig = BaseNormalisedOverrideConfigWithoutAPI[
    RecipeInterface
]
InputOverrideConfig = AccountLinkingOverrideConfig
"""Deprecated, use `AccountLinkingOverrideConfig` instead."""


class AccountInfoWithRecipeId(AccountInfo):
    def __init__(
        self,
        recipe_id: Literal["emailpassword", "thirdparty", "passwordless", "webauthn"],
        email: Optional[str] = None,
        phone_number: Optional[str] = None,
        third_party: Optional[ThirdPartyInfo] = None,
        webauthn: Optional[WebauthnInfo] = None,
    ):
        super().__init__(email, phone_number, third_party, webauthn=webauthn)
        self.recipe_id: Literal[
            "emailpassword", "thirdparty", "passwordless", "webauthn"
        ] = recipe_id

    def to_json(self) -> Dict[str, Any]:
        return {
            **super().to_json(),
            "recipeId": self.recipe_id,
        }


class RecipeLevelUser(AccountInfoWithRecipeId):
    def __init__(
        self,
        tenant_ids: List[str],
        time_joined: int,
        recipe_id: Literal["emailpassword", "thirdparty", "passwordless", "webauthn"],
        email: Optional[str] = None,
        phone_number: Optional[str] = None,
        third_party: Optional[ThirdPartyInfo] = None,
        webauthn: Optional[WebauthnInfo] = None,
    ):
        super().__init__(recipe_id, email, phone_number, third_party, webauthn=webauthn)
        self.tenant_ids = tenant_ids
        self.time_joined = time_joined
        self.recipe_id: Literal[
            "emailpassword", "thirdparty", "passwordless", "webauthn"
        ] = recipe_id

    @staticmethod
    def from_login_method(
        login_method: LoginMethod,
    ) -> RecipeLevelUser:
        return RecipeLevelUser(
            tenant_ids=login_method.tenant_ids,
            time_joined=login_method.time_joined,
            recipe_id=login_method.recipe_id,
            email=login_method.email,
            phone_number=login_method.phone_number,
            third_party=login_method.third_party,
            webauthn=login_method.webauthn,
        )


class AccountInfoWithRecipeIdAndUserId(AccountInfoWithRecipeId):
    def __init__(
        self,
        recipe_user_id: Optional[RecipeUserId],
        recipe_id: Literal["emailpassword", "thirdparty", "passwordless", "webauthn"],
        email: Optional[str] = None,
        phone_number: Optional[str] = None,
        third_party: Optional[ThirdPartyInfo] = None,
        webauthn: Optional[WebauthnInfo] = None,
    ):
        super().__init__(recipe_id, email, phone_number, third_party, webauthn=webauthn)
        self.recipe_user_id = recipe_user_id

    @staticmethod
    def from_account_info_or_login_method(
        account_info: Union[AccountInfoWithRecipeId, LoginMethod],
    ) -> AccountInfoWithRecipeIdAndUserId:
        from supertokens_python.types import (
            LoginMethod as LM,
        )

        return AccountInfoWithRecipeIdAndUserId(
            recipe_id=account_info.recipe_id,
            email=account_info.email,
            phone_number=account_info.phone_number,
            third_party=account_info.third_party,
            webauthn=account_info.webauthn,
            recipe_user_id=(
                account_info.recipe_user_id if isinstance(account_info, LM) else None
            ),
        )


class ShouldNotAutomaticallyLink:
    def __init__(self):
        pass


class ShouldAutomaticallyLink:
    def __init__(self, should_require_verification: bool):
        self.should_require_verification = should_require_verification


class AccountLinkingOverrideableConfig(BaseOverrideableConfig):
    """Input config properties overrideable using the plugin config overrides"""

    on_account_linked: Optional[
        Callable[[User, RecipeLevelUser, Dict[str, Any]], Awaitable[None]]
    ] = None
    should_do_automatic_account_linking: Optional[
        Callable[
            [
                AccountInfoWithRecipeIdAndUserId,
                Optional[User],
                Optional[SessionContainer],
                str,
                Dict[str, Any],
            ],
            Awaitable[Union[ShouldNotAutomaticallyLink, ShouldAutomaticallyLink]],
        ]
    ] = None


class AccountLinkingConfig(
    AccountLinkingOverrideableConfig,
    BaseConfigWithoutAPIOverride[RecipeInterface, AccountLinkingOverrideableConfig],
):
    def to_overrideable_config(self) -> AccountLinkingOverrideableConfig:
        """Create a `AccountLinkingOverrideableConfig` from the current config."""
        return AccountLinkingOverrideableConfig(**self.model_dump())

    def from_overrideable_config(
        self,
        overrideable_config: AccountLinkingOverrideableConfig,
    ) -> "AccountLinkingConfig":
        """
        Create a `AccountLinkingConfig` from a `AccountLinkingOverrideableConfig`.
        Not a classmethod since it needs to be used in a dynamic context within plugins.
        """
        return AccountLinkingConfig(
            **overrideable_config.model_dump(),
            override=self.override,
        )


class NormalisedAccountLinkingConfig(
    BaseNormalisedConfigWithoutAPIOverride[RecipeInterface]
):
    on_account_linked: Callable[
        [User, RecipeLevelUser, Dict[str, Any]], Awaitable[None]
    ]
    should_do_automatic_account_linking: Callable[
        [
            AccountInfoWithRecipeIdAndUserId,
            Optional[User],
            Optional[SessionContainer],
            str,
            Dict[str, Any],
        ],
        Awaitable[Union[ShouldNotAutomaticallyLink, ShouldAutomaticallyLink]],
    ]

Classes

class AccountInfoWithRecipeId (recipe_id: "Literal['emailpassword', 'thirdparty', 'passwordless', 'webauthn']", email: Optional[str] = None, phone_number: Optional[str] = None, third_party: Optional[ThirdPartyInfo] = None, webauthn: Optional[WebauthnInfo] = None)
Expand source code
class AccountInfoWithRecipeId(AccountInfo):
    def __init__(
        self,
        recipe_id: Literal["emailpassword", "thirdparty", "passwordless", "webauthn"],
        email: Optional[str] = None,
        phone_number: Optional[str] = None,
        third_party: Optional[ThirdPartyInfo] = None,
        webauthn: Optional[WebauthnInfo] = None,
    ):
        super().__init__(email, phone_number, third_party, webauthn=webauthn)
        self.recipe_id: Literal[
            "emailpassword", "thirdparty", "passwordless", "webauthn"
        ] = recipe_id

    def to_json(self) -> Dict[str, Any]:
        return {
            **super().to_json(),
            "recipeId": self.recipe_id,
        }

Ancestors

Subclasses

Methods

def to_json(self) ‑> Dict[str, Any]
class AccountInfoWithRecipeIdAndUserId (recipe_user_id: Optional[RecipeUserId], recipe_id: "Literal['emailpassword', 'thirdparty', 'passwordless', 'webauthn']", email: Optional[str] = None, phone_number: Optional[str] = None, third_party: Optional[ThirdPartyInfo] = None, webauthn: Optional[WebauthnInfo] = None)
Expand source code
class AccountInfoWithRecipeIdAndUserId(AccountInfoWithRecipeId):
    def __init__(
        self,
        recipe_user_id: Optional[RecipeUserId],
        recipe_id: Literal["emailpassword", "thirdparty", "passwordless", "webauthn"],
        email: Optional[str] = None,
        phone_number: Optional[str] = None,
        third_party: Optional[ThirdPartyInfo] = None,
        webauthn: Optional[WebauthnInfo] = None,
    ):
        super().__init__(recipe_id, email, phone_number, third_party, webauthn=webauthn)
        self.recipe_user_id = recipe_user_id

    @staticmethod
    def from_account_info_or_login_method(
        account_info: Union[AccountInfoWithRecipeId, LoginMethod],
    ) -> AccountInfoWithRecipeIdAndUserId:
        from supertokens_python.types import (
            LoginMethod as LM,
        )

        return AccountInfoWithRecipeIdAndUserId(
            recipe_id=account_info.recipe_id,
            email=account_info.email,
            phone_number=account_info.phone_number,
            third_party=account_info.third_party,
            webauthn=account_info.webauthn,
            recipe_user_id=(
                account_info.recipe_user_id if isinstance(account_info, LM) else None
            ),
        )

Ancestors

Static methods

def from_account_info_or_login_method(account_info: Union[AccountInfoWithRecipeId, LoginMethod]) ‑> AccountInfoWithRecipeIdAndUserId
class AccountLinkingConfig (**data: Any)

Input config properties overrideable using the plugin config 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.

self is explicitly positional-only to allow self as a field name.

Expand source code
class AccountLinkingConfig(
    AccountLinkingOverrideableConfig,
    BaseConfigWithoutAPIOverride[RecipeInterface, AccountLinkingOverrideableConfig],
):
    def to_overrideable_config(self) -> AccountLinkingOverrideableConfig:
        """Create a `AccountLinkingOverrideableConfig` from the current config."""
        return AccountLinkingOverrideableConfig(**self.model_dump())

    def from_overrideable_config(
        self,
        overrideable_config: AccountLinkingOverrideableConfig,
    ) -> "AccountLinkingConfig":
        """
        Create a `AccountLinkingConfig` from a `AccountLinkingOverrideableConfig`.
        Not a classmethod since it needs to be used in a dynamic context within plugins.
        """
        return AccountLinkingConfig(
            **overrideable_config.model_dump(),
            override=self.override,
        )

Ancestors

Methods

def from_overrideable_config(self, overrideable_config: AccountLinkingOverrideableConfig) ‑> AccountLinkingConfig

Create a AccountLinkingConfig from a AccountLinkingOverrideableConfig. Not a classmethod since it needs to be used in a dynamic context within plugins.

def to_overrideable_config(self) ‑> AccountLinkingOverrideableConfig

Create a AccountLinkingOverrideableConfig from the current config.

Inherited members

class AccountLinkingOverrideableConfig (**data: Any)

Input config properties overrideable using the plugin config 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.

self is explicitly positional-only to allow self as a field name.

Expand source code
class AccountLinkingOverrideableConfig(BaseOverrideableConfig):
    """Input config properties overrideable using the plugin config overrides"""

    on_account_linked: Optional[
        Callable[[User, RecipeLevelUser, Dict[str, Any]], Awaitable[None]]
    ] = None
    should_do_automatic_account_linking: Optional[
        Callable[
            [
                AccountInfoWithRecipeIdAndUserId,
                Optional[User],
                Optional[SessionContainer],
                str,
                Dict[str, Any],
            ],
            Awaitable[Union[ShouldNotAutomaticallyLink, ShouldAutomaticallyLink]],
        ]
    ] = None

Ancestors

Subclasses

Class variables

var on_account_linked : Optional[Callable[[UserRecipeLevelUser, Dict[str, Any]], Awaitable[None]]]

The type of the None singleton.

var should_do_automatic_account_linking : Optional[Callable[[AccountInfoWithRecipeIdAndUserId, Optional[User], Optional[SessionContainer], str, Dict[str, Any]], Awaitable[Union[ShouldNotAutomaticallyLinkShouldAutomaticallyLink]]]]

The type of the None singleton.

Inherited members

class InputOverrideConfig (**data: Any)

Base class for input override config without 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.

self is explicitly positional-only to allow self as a field name.

Ancestors

Inherited members

class NormalisedAccountLinkingConfig (**data: Any)

Base class for normalized config of a Recipe without 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.

self is explicitly positional-only to allow self as a field name.

Expand source code
class NormalisedAccountLinkingConfig(
    BaseNormalisedConfigWithoutAPIOverride[RecipeInterface]
):
    on_account_linked: Callable[
        [User, RecipeLevelUser, Dict[str, Any]], Awaitable[None]
    ]
    should_do_automatic_account_linking: Callable[
        [
            AccountInfoWithRecipeIdAndUserId,
            Optional[User],
            Optional[SessionContainer],
            str,
            Dict[str, Any],
        ],
        Awaitable[Union[ShouldNotAutomaticallyLink, ShouldAutomaticallyLink]],
    ]

Ancestors

Class variables

var on_account_linked : Callable[[UserRecipeLevelUser, Dict[str, Any]], Awaitable[None]]

The type of the None singleton.

var should_do_automatic_account_linking : Callable[[AccountInfoWithRecipeIdAndUserId, Optional[User], Optional[SessionContainer], str, Dict[str, Any]], Awaitable[Union[ShouldNotAutomaticallyLinkShouldAutomaticallyLink]]]

The type of the None singleton.

Inherited members

class RecipeLevelUser (tenant_ids: List[str], time_joined: int, recipe_id: "Literal['emailpassword', 'thirdparty', 'passwordless', 'webauthn']", email: Optional[str] = None, phone_number: Optional[str] = None, third_party: Optional[ThirdPartyInfo] = None, webauthn: Optional[WebauthnInfo] = None)
Expand source code
class RecipeLevelUser(AccountInfoWithRecipeId):
    def __init__(
        self,
        tenant_ids: List[str],
        time_joined: int,
        recipe_id: Literal["emailpassword", "thirdparty", "passwordless", "webauthn"],
        email: Optional[str] = None,
        phone_number: Optional[str] = None,
        third_party: Optional[ThirdPartyInfo] = None,
        webauthn: Optional[WebauthnInfo] = None,
    ):
        super().__init__(recipe_id, email, phone_number, third_party, webauthn=webauthn)
        self.tenant_ids = tenant_ids
        self.time_joined = time_joined
        self.recipe_id: Literal[
            "emailpassword", "thirdparty", "passwordless", "webauthn"
        ] = recipe_id

    @staticmethod
    def from_login_method(
        login_method: LoginMethod,
    ) -> RecipeLevelUser:
        return RecipeLevelUser(
            tenant_ids=login_method.tenant_ids,
            time_joined=login_method.time_joined,
            recipe_id=login_method.recipe_id,
            email=login_method.email,
            phone_number=login_method.phone_number,
            third_party=login_method.third_party,
            webauthn=login_method.webauthn,
        )

Ancestors

Static methods

def from_login_method(login_method: LoginMethod) ‑> RecipeLevelUser
Expand source code
class ShouldAutomaticallyLink:
    def __init__(self, should_require_verification: bool):
        self.should_require_verification = should_require_verification
Expand source code
class ShouldNotAutomaticallyLink:
    def __init__(self):
        pass