from __future__ import annotations from datetime import datetime from time import time from typing import Any, Callable, Dict, List, Optional, Union from pydantic import BaseModel, ConfigDict try: # > 2 from pydantic import model_validator model_validator_v1_v2_compat = model_validator(mode="before") except ImportError: # < 2 from pydantic import root_validator model_validator_v1_v2_compat = root_validator from typing_extensions import Literal, NotRequired, TypedDict Provider = Literal[ "apple", "azure", "bitbucket", "discord", "facebook", "figma", "fly", "github", "gitlab", "google", "kakao", "keycloak", "linkedin", "linkedin_oidc", "notion", "slack", "slack_oidc", "spotify", "twitch", "twitter", "workos", "zoom", ] EmailOtpType = Literal[ "signup", "invite", "magiclink", "recovery", "email_change", "email" ] AuthChangeEventMFA = Literal["MFA_CHALLENGE_VERIFIED"] AuthFlowType = Literal["pkce", "implicit"] AuthChangeEvent = Literal[ "PASSWORD_RECOVERY", "SIGNED_IN", "SIGNED_OUT", "TOKEN_REFRESHED", "USER_UPDATED", "USER_DELETED", AuthChangeEventMFA, ] class AMREntry(BaseModel): """ An authentication methord reference (AMR) entry. An entry designates what method was used by the user to verify their identity and at what time. """ method: Union[Literal["password", "otp", "oauth", "mfa/totp"], str] """ Authentication method name. """ timestamp: int """ Timestamp when the method was successfully used. Represents number of seconds since 1st January 1970 (UNIX epoch) in UTC. """ class Options(TypedDict): redirect_to: NotRequired[str] captcha_token: NotRequired[str] class InviteUserByEmailOptions(TypedDict): redirect_to: NotRequired[str] data: NotRequired[Any] class AuthResponse(BaseModel): user: Optional[User] = None session: Optional[Session] = None class AuthOtpResponse(BaseModel): user: None = None session: None = None message_id: Optional[str] = None class OAuthResponse(BaseModel): provider: Provider url: str class SSOResponse(BaseModel): url: str class LinkIdentityResponse(BaseModel): url: str class IdentitiesResponse(BaseModel): identities: List[UserIdentity] class UserResponse(BaseModel): user: User class Session(BaseModel): provider_token: Optional[str] = None """ The oauth provider token. If present, this can be used to make external API requests to the oauth provider used. """ provider_refresh_token: Optional[str] = None """ The oauth provider refresh token. If present, this can be used to refresh the provider_token via the oauth provider's API. Not all oauth providers return a provider refresh token. If the provider_refresh_token is missing, please refer to the oauth provider's documentation for information on how to obtain the provider refresh token. """ access_token: str refresh_token: str expires_in: int """ The number of seconds until the token expires (since it was issued). Returned when a login is confirmed. """ expires_at: Optional[int] = None """ A timestamp of when the token will expire. Returned when a login is confirmed. """ token_type: str user: User @model_validator_v1_v2_compat def validator(cls, values: dict) -> dict: expires_in = values.get("expires_in") if expires_in and not values.get("expires_at"): values["expires_at"] = round(time()) + expires_in return values class UserIdentity(BaseModel): id: str identity_id: str user_id: str identity_data: Dict[str, Any] provider: str created_at: datetime last_sign_in_at: Optional[datetime] = None updated_at: Optional[datetime] = None class Factor(BaseModel): """ A MFA factor. """ id: str """ ID of the factor. """ friendly_name: Optional[str] = None """ Friendly name of the factor, useful to disambiguate between multiple factors. """ factor_type: Union[Literal["totp", "phone"], str] """ Type of factor. Only `totp` supported with this version but may change in future versions. """ status: Literal["verified", "unverified"] """ Factor's status. """ created_at: datetime updated_at: datetime class User(BaseModel): id: str app_metadata: Dict[str, Any] user_metadata: Dict[str, Any] aud: str confirmation_sent_at: Optional[datetime] = None recovery_sent_at: Optional[datetime] = None email_change_sent_at: Optional[datetime] = None new_email: Optional[str] = None new_phone: Optional[str] = None invited_at: Optional[datetime] = None action_link: Optional[str] = None email: Optional[str] = None phone: Optional[str] = None created_at: datetime confirmed_at: Optional[datetime] = None email_confirmed_at: Optional[datetime] = None phone_confirmed_at: Optional[datetime] = None last_sign_in_at: Optional[datetime] = None role: Optional[str] = None updated_at: Optional[datetime] = None identities: Optional[List[UserIdentity]] = None is_anonymous: bool = False factors: Optional[List[Factor]] = None class UserAttributes(TypedDict): email: NotRequired[str] phone: NotRequired[str] password: NotRequired[str] data: NotRequired[Any] class AdminUserAttributes(UserAttributes, TypedDict): user_metadata: NotRequired[Any] app_metadata: NotRequired[Any] email_confirm: NotRequired[bool] phone_confirm: NotRequired[bool] ban_duration: NotRequired[Union[str, Literal["none"]]] role: NotRequired[str] """ The `role` claim set in the user's access token JWT. When a user signs up, this role is set to `authenticated` by default. You should only modify the `role` if you need to provision several levels of admin access that have different permissions on individual columns in your database. Setting this role to `service_role` is not recommended as it grants the user admin privileges. """ password_hash: NotRequired[str] """ The `password_hash` for the user's password. Allows you to specify a password hash for the user. This is useful for migrating a user's password hash from another service. Supports bcrypt and argon2 password hashes. """ id: NotRequired[str] """ The `id` for the user. Allows you to overwrite the default `id` set for the user. """ class Subscription(BaseModel): id: str """ The subscriber UUID. This will be set by the client. """ callback: Callable[[AuthChangeEvent, Optional[Session]], None] """ The function to call every time there is an event. """ unsubscribe: Callable[[], None] """ Call this to remove the listener. """ class UpdatableFactorAttributes(TypedDict): friendly_name: str class SignUpWithEmailAndPasswordCredentialsOptions( TypedDict, ): email_redirect_to: NotRequired[str] data: NotRequired[Any] captcha_token: NotRequired[str] class SignUpWithEmailAndPasswordCredentials(TypedDict): email: str password: str options: NotRequired[SignUpWithEmailAndPasswordCredentialsOptions] class SignUpWithPhoneAndPasswordCredentialsOptions(TypedDict): data: NotRequired[Any] captcha_token: NotRequired[str] channel: NotRequired[Literal["sms", "whatsapp"]] class SignUpWithPhoneAndPasswordCredentials(TypedDict): phone: str password: str options: NotRequired[SignUpWithPhoneAndPasswordCredentialsOptions] SignUpWithPasswordCredentials = Union[ SignUpWithEmailAndPasswordCredentials, SignUpWithPhoneAndPasswordCredentials, ] class SignInWithPasswordCredentialsOptions(TypedDict): data: NotRequired[Any] captcha_token: NotRequired[str] class SignInWithEmailAndPasswordCredentials(TypedDict): email: str password: str options: NotRequired[SignInWithPasswordCredentialsOptions] class SignInWithPhoneAndPasswordCredentials(TypedDict): phone: str password: str options: NotRequired[SignInWithPasswordCredentialsOptions] SignInWithPasswordCredentials = Union[ SignInWithEmailAndPasswordCredentials, SignInWithPhoneAndPasswordCredentials, ] class SignInWithIdTokenCredentials(TypedDict): """ Provider name or OIDC `iss` value identifying which provider should be used to verify the provided token. Supported names: `google`, `apple`, `azure`, `facebook`, `kakao`, `keycloak` (deprecated). """ provider: Literal["google", "apple", "azure", "facebook", "kakao"] token: str access_token: NotRequired[str] nonce: NotRequired[str] options: NotRequired[SignInWithIdTokenCredentialsOptions] class SignInWithIdTokenCredentialsOptions(TypedDict): captcha_token: NotRequired[str] class SignInWithEmailAndPasswordlessCredentialsOptions(TypedDict): email_redirect_to: NotRequired[str] should_create_user: NotRequired[bool] data: NotRequired[Any] captcha_token: NotRequired[str] class SignInWithEmailAndPasswordlessCredentials(TypedDict): email: str options: NotRequired[SignInWithEmailAndPasswordlessCredentialsOptions] class SignInWithPhoneAndPasswordlessCredentialsOptions(TypedDict): should_create_user: NotRequired[bool] data: NotRequired[Any] captcha_token: NotRequired[str] channel: NotRequired[Literal["sms", "whatsapp"]] class SignInWithPhoneAndPasswordlessCredentials(TypedDict): phone: str options: NotRequired[SignInWithPhoneAndPasswordlessCredentialsOptions] SignInWithPasswordlessCredentials = Union[ SignInWithEmailAndPasswordlessCredentials, SignInWithPhoneAndPasswordlessCredentials, ] class ResendEmailCredentialsOptions(TypedDict): email_redirect_to: NotRequired[str] captcha_token: NotRequired[str] class ResendEmailCredentials(TypedDict): type: Literal["signup", "email_change"] email: str options: NotRequired[ResendEmailCredentialsOptions] class ResendPhoneCredentialsOptions(TypedDict): captcha_token: NotRequired[str] class ResendPhoneCredentials(TypedDict): type: Literal["sms", "phone_change"] phone: str options: NotRequired[ResendPhoneCredentialsOptions] ResendCredentials = Union[ResendEmailCredentials, ResendPhoneCredentials] class SignInWithOAuthCredentialsOptions(TypedDict): redirect_to: NotRequired[str] scopes: NotRequired[str] query_params: NotRequired[Dict[str, str]] class SignInWithOAuthCredentials(TypedDict): provider: Provider options: NotRequired[SignInWithOAuthCredentialsOptions] class SignInWithSSOCredentials(TypedDict): provider_id: NotRequired[str] domain: NotRequired[str] options: NotRequired[SignInWithSSOOptions] class SignInWithSSOOptions(TypedDict): redirect_to: NotRequired[str] skip_http_redirect: NotRequired[bool] class SignInAnonymouslyCredentials(TypedDict): options: NotRequired[SignInAnonymouslyCredentialsOptions] class SignInAnonymouslyCredentialsOptions(TypedDict): data: NotRequired[Any] captcha_token: NotRequired[str] class VerifyOtpParamsOptions(TypedDict): redirect_to: NotRequired[str] captcha_token: NotRequired[str] class VerifyEmailOtpParams(TypedDict): email: str token: str type: EmailOtpType options: NotRequired[VerifyOtpParamsOptions] class VerifyMobileOtpParams(TypedDict): phone: str token: str type: Literal[ "sms", "phone_change", ] options: NotRequired[VerifyOtpParamsOptions] class VerifyTokenHashParams(TypedDict): token_hash: str type: EmailOtpType options: NotRequired[VerifyOtpParamsOptions] VerifyOtpParams = Union[ VerifyEmailOtpParams, VerifyMobileOtpParams, VerifyTokenHashParams ] class GenerateLinkParamsOptions(TypedDict): redirect_to: NotRequired[str] class GenerateLinkParamsWithDataOptions(GenerateLinkParamsOptions, TypedDict): data: NotRequired[Any] class GenerateSignupLinkParams(TypedDict): type: Literal["signup"] email: str password: str options: NotRequired[GenerateLinkParamsWithDataOptions] class GenerateInviteOrMagiclinkParams(TypedDict): type: Literal["invite", "magiclink"] email: str options: NotRequired[GenerateLinkParamsWithDataOptions] class GenerateRecoveryLinkParams(TypedDict): type: Literal["recovery"] email: str options: NotRequired[GenerateLinkParamsOptions] class GenerateEmailChangeLinkParams(TypedDict): type: Literal["email_change_current", "email_change_new"] email: str new_email: str options: NotRequired[GenerateLinkParamsOptions] GenerateLinkParams = Union[ GenerateSignupLinkParams, GenerateInviteOrMagiclinkParams, GenerateRecoveryLinkParams, GenerateEmailChangeLinkParams, ] GenerateLinkType = Literal[ "signup", "invite", "magiclink", "recovery", "email_change_current", "email_change_new", ] class MFAEnrollParams(TypedDict): factor_type: Literal["totp", "phone"] issuer: NotRequired[str] friendly_name: NotRequired[str] phone: str class MFAUnenrollParams(TypedDict): factor_id: str """ ID of the factor being unenrolled. """ class CodeExchangeParams(TypedDict): code_verifier: str """ Randomly generated string """ auth_code: str """ Code returned after completing one of the authorization flows """ redirect_to: str """ The URL to route to after a session is successfully obtained """ class MFAVerifyParams(TypedDict): factor_id: str """ ID of the factor being verified. """ challenge_id: str """ ID of the challenge being verified. """ code: str """ Verification code provided by the user. """ class MFAChallengeParams(TypedDict): factor_id: str """ ID of the factor to be challenged. """ channel: NotRequired[Literal["sms", "whatsapp"]] class MFAChallengeAndVerifyParams(TypedDict): factor_id: str """ ID of the factor being verified. """ code: str """ Verification code provided by the user. """ class AuthMFAVerifyResponse(BaseModel): access_token: str """ New access token (JWT) after successful verification. """ token_type: str """ Type of token, typically `Bearer`. """ expires_in: int """ Number of seconds in which the access token will expire. """ refresh_token: str """ Refresh token you can use to obtain new access tokens when expired. """ user: User """ Updated user profile. """ class AuthMFAEnrollResponseTotp(BaseModel): qr_code: str """ Contains a QR code encoding the authenticator URI. You can convert it to a URL by prepending `data:image/svg+xml;utf-8,` to the value. Avoid logging this value to the console. """ secret: str """ The TOTP secret (also encoded in the QR code). Show this secret in a password-style field to the user, in case they are unable to scan the QR code. Avoid logging this value to the console. """ uri: str """ The authenticator URI encoded within the QR code, should you need to use it. Avoid loggin this value to the console. """ class AuthMFAEnrollResponse(BaseModel): id: str """ ID of the factor that was just enrolled (in an unverified state). """ type: Literal["totp", "phone"] """ Type of MFA factor. Only `totp` supported for now. """ totp: AuthMFAEnrollResponseTotp """ TOTP enrollment information. """ model_config = ConfigDict(arbitrary_types_allowed=True) friendly_name: str """ Friendly name of the factor, useful for distinguishing between factors """ phone: str """ Phone number of the MFA factor in E.164 format. Used to send messages """ class AuthMFAUnenrollResponse(BaseModel): id: str """ ID of the factor that was successfully unenrolled. """ class AuthMFAChallengeResponse(BaseModel): id: str """ ID of the newly created challenge. """ expires_at: int """ Timestamp in UNIX seconds when this challenge will no longer be usable. """ factor_type: Literal["totp", "phone"] """ Factor Type which generated the challenge """ class AuthMFAListFactorsResponse(BaseModel): all: List[Factor] """ All available factors (verified and unverified). """ totp: List[Factor] """ Only verified TOTP factors. (A subset of `all`.) """ phone: List[Factor] """ Only verified Phone factors. (A subset of `all`.) """ AuthenticatorAssuranceLevels = Literal["aal1", "aal2"] class AuthMFAGetAuthenticatorAssuranceLevelResponse(BaseModel): current_level: Optional[AuthenticatorAssuranceLevels] = None """ Current AAL level of the session. """ next_level: Optional[AuthenticatorAssuranceLevels] = None """ Next possible AAL level for the session. If the next level is higher than the current one, the user should go through MFA. """ current_authentication_methods: List[AMREntry] """ A list of all authentication methods attached to this session. Use the information here to detect the last time a user verified a factor, for example if implementing a step-up scenario. """ class AuthMFAAdminDeleteFactorResponse(BaseModel): id: str """ ID of the factor that was successfully deleted. """ class AuthMFAAdminDeleteFactorParams(TypedDict): id: str """ ID of the MFA factor to delete. """ user_id: str """ ID of the user whose factor is being deleted. """ class AuthMFAAdminListFactorsResponse(BaseModel): factors: List[Factor] """ All factors attached to the user. """ class AuthMFAAdminListFactorsParams(TypedDict): user_id: str """ ID of the user for which to list all MFA factors. """ class GenerateLinkProperties(BaseModel): """ The properties related to the email link generated. """ action_link: str """ The email link to send to the user. The action_link follows the following format: auth/v1/verify?type={verification_type}&token={hashed_token}&redirect_to={redirect_to} """ email_otp: str """ The raw email OTP. You should send this in the email if you want your users to verify using an OTP instead of the action link. """ hashed_token: str """ The hashed token appended to the action link. """ redirect_to: str """ The URL appended to the action link. """ verification_type: GenerateLinkType """ The verification type that the email link is associated to. """ class GenerateLinkResponse(BaseModel): properties: GenerateLinkProperties user: User class DecodedJWTDict(TypedDict): exp: NotRequired[int] aal: NotRequired[Optional[AuthenticatorAssuranceLevels]] amr: NotRequired[Optional[List[AMREntry]]] SignOutScope = Literal["global", "local", "others"] class SignOutOptions(TypedDict): scope: NotRequired[SignOutScope] for model in [ AMREntry, AuthResponse, OAuthResponse, UserResponse, Session, UserIdentity, Factor, User, Subscription, AuthMFAVerifyResponse, AuthMFAEnrollResponseTotp, AuthMFAEnrollResponse, AuthMFAUnenrollResponse, AuthMFAChallengeResponse, AuthMFAListFactorsResponse, AuthMFAGetAuthenticatorAssuranceLevelResponse, AuthMFAAdminDeleteFactorResponse, AuthMFAAdminListFactorsResponse, GenerateLinkProperties, ]: try: # pydantic > 2 model.model_rebuild() except AttributeError: # pydantic < 2 model.update_forward_refs()