From bd405d063e42842a84b475e2bba951c7b284b3c9 Mon Sep 17 00:00:00 2001
From: "promptless[bot]" <179508745+promptless[bot]@users.noreply.github.com>
Date: Thu, 26 Jun 2025 16:32:43 +0000
Subject: [PATCH 01/10] Documentation updates from Promptless
---
.../mfa/important-concepts.mdx | 1 +
.../mfa/introduction.mdx | 4 +-
docs/authentication/overview.mdx | 11 +-
.../authentication/passkeys/customization.mdx | 186 ++++++++++++++++--
.../authentication/passkeys/initial-setup.mdx | 35 +++-
5 files changed, 216 insertions(+), 21 deletions(-)
diff --git a/docs/additional-verification/mfa/important-concepts.mdx b/docs/additional-verification/mfa/important-concepts.mdx
index 34eb2e988..271580daf 100644
--- a/docs/additional-verification/mfa/important-concepts.mdx
+++ b/docs/additional-verification/mfa/important-concepts.mdx
@@ -65,6 +65,7 @@ Each auth challenge has a factor ID in SuperTokens:
| Passwordless - Email magic link | `link-email` |
| Passwordless - SMS magic link | `link-phone` |
| TOTP | `totp` |
+| WebAuthn (Passkeys) | `webauthn` |
These factor IDs get used to configure the MFA requirements for users (except the `acccess-denied` one).
They are also used to indicate which authentication challenges have completed in the current session.
diff --git a/docs/additional-verification/mfa/introduction.mdx b/docs/additional-verification/mfa/introduction.mdx
index 612760982..9c58047e7 100644
--- a/docs/additional-verification/mfa/introduction.mdx
+++ b/docs/additional-verification/mfa/introduction.mdx
@@ -4,7 +4,7 @@ title: Introduction
hide_title: true
skip_llms_txt: true
description: >-
- Implement multi-factor authentication with email, SMS, or TOTP, and customize
+ Implement multi-factor authentication with email, SMS, TOTP, or WebAuthn, and customize
user authentication preferences.
page_type: overview
recipe: mfa
@@ -17,7 +17,7 @@ category: multi-factor-authentication
## Overview
Multi-factor authentication (MFA) is a security process that requires users to verify their identity through multiple forms of credentials before gaining access to a system.
-**SuperTokens** allows you to integrate MFA in your application using either Email/SMS One-Time Password (OTP) or Time-based One-Time Password (TOTP).
+**SuperTokens** allows you to integrate MFA in your application using Email/SMS One-Time Password (OTP), Time-based One-Time Password (TOTP), or WebAuthn (Passkeys).
## Prerequisites
diff --git a/docs/authentication/overview.mdx b/docs/authentication/overview.mdx
index 84649d442..f0e5fac0e 100644
--- a/docs/authentication/overview.mdx
+++ b/docs/authentication/overview.mdx
@@ -45,6 +45,15 @@ Discover all the ways in which you can authenticate your users with **SuperToken
Login flow that uses third-party providers for authentication.
+
+
+ Passkeys
+
+
+ Passwordless authentication using biometrics, security keys, or device-based credentials.
+
+
+
Enterprise Login
@@ -53,7 +62,6 @@ Discover all the ways in which you can authenticate your users with **SuperToken
Instructions on how to configure your application to support multiple tenants and enterprise authentication methods.
-
Unified Login
@@ -62,6 +70,7 @@ Discover all the ways in which you can authenticate your users with **SuperToken
Details on how to create a common authentication experience for all your products.
+
Machine to Machine Authentication
diff --git a/docs/authentication/passkeys/customization.mdx b/docs/authentication/passkeys/customization.mdx
index 8d2abea47..931dd805f 100644
--- a/docs/authentication/passkeys/customization.mdx
+++ b/docs/authentication/passkeys/customization.mdx
@@ -87,11 +87,45 @@ At the moment there is no support for using passkeys authentication in the Go SD
-:::caution
-
-At the moment there is no support for using passkeys authentication in the Python SDK.
-
-:::
+```python
+from supertokens_python import init, InputAppInfo, SupertokensConfig
+from supertokens_python.recipe import webauthn, session
+
+def get_origin(tenant_id: str, request, user_context):
+ return "https://example.com"
+
+def get_relying_party_id(tenant_id: str, request, user_context):
+ return "example.com"
+
+def get_relying_party_name(tenant_id: str, request, user_context):
+ return "example"
+
+init(
+ app_info=InputAppInfo(
+ app_name="",
+ api_domain="",
+ website_domain="",
+ api_base_path="/auth",
+ website_base_path="/auth"
+ ),
+ supertokens_config=SupertokensConfig(
+ # https://try.supertokens.com is for demo purposes. Replace this with the address of your core instance (sign up on supertokens.com), or self host a core.
+ connection_uri="https://try.supertokens.com",
+ # api_key=""
+ ),
+ framework='flask', # Replace this with the framework you are using
+ recipe_list=[
+ webauthn.init(
+ config=webauthn.WebauthnConfig(
+ get_origin=get_origin,
+ get_relying_party_id=get_relying_party_id,
+ get_relying_party_name=get_relying_party_name,
+ )
+ ),
+ session.init() # initializes session features
+ ]
+)
+```
@@ -190,11 +224,84 @@ At the moment there is no support for using passkeys authentication in the Go SD
-:::caution
+```python
+from supertokens_python import init, InputAppInfo, SupertokensConfig
+from supertokens_python.recipe import webauthn, session
+from typing import Dict, Any, List, Optional, Union
+from typing_extensions import Unpack
+
+def override_webauthn_functions(original_implementation: webauthn.RecipeInterface):
+ original_register_options = original_implementation.register_options
+
+ async def register_options(
+ email: Optional[str],
+ recover_account_token: Optional[str],
+ tenant_id: str,
+ user_context: Dict[str, Any],
+ **kwargs: Unpack[webauthn.RegisterOptionsKwargsInput]
+ ):
+ return await original_register_options(
+ email=email,
+ recover_account_token=recover_account_token,
+ tenant_id=tenant_id,
+ user_context=user_context,
+ attestation="direct",
+ resident_key="required",
+ timeout=10 * 1000,
+ user_verification="required",
+ display_name="John Doe",
+ supported_algorithms=[-257],
+ relying_party_id='example.com',
+ relying_party_name='example',
+ origin='https://example.com',
+ )
+
+ original_implementation.register_options = register_options
+ return original_implementation
+
+init(
+ app_info=InputAppInfo(
+ app_name="",
+ api_domain="",
+ website_domain="",
+ api_base_path="/auth",
+ website_base_path="/auth"
+ ),
+ supertokens_config=SupertokensConfig(
+ # https://try.supertokens.com is for demo purposes. Replace this with the address of your core instance (sign up on supertokens.com), or self host a core.
+ connection_uri="https://try.supertokens.com",
+ # api_key=""
+ ),
+ framework='flask', # Replace this with the framework you are using
+ recipe_list=[
+ webauthn.init(
+ config=webauthn.WebauthnConfig(
+ override=webauthn.OverrideConfig(
+ functions=override_webauthn_functions
+ )
+ )
+ ),
+ session.init() # initializes session features
+ ]
+)
+```
-At the moment there is no support for using passkeys authentication in the Python SDK.
+
+
+#### Input properties
+
+| Name | Type | Description | Default Value |
+|----------|----------|-------------|---------------|
+| `relying_party_id` | `str` | The domain name of your application that the system uses for validating the credential. | Uses `get_relying_party_id` from the recipe configuration which defaults to the `api_domain` |
+| `relying_party_name` | `str` | The human-readable name of your application. | Uses `get_relying_party_name` from the recipe configuration which defaults to the `app_name` |
+| `origin` | `str` | The origin URL where the credential is generated. | Uses `get_origin` from the recipe configuration which defaults to the origin of the request |
+| `timeout` | `int` | The time in milliseconds that the user has to complete the credential generation process. | `6000` |
+| `attestation` | `"none" \| "indirect" \| "direct" \| "enterprise"` | The amount of information about the authenticator that gets included in the attestation statement. This controls what authenticators support. | `none` |
+| `supported_algorithms` | `List[int]` | The cryptographic algorithms that can generate credentials. Different authenticators support different algorithms. | `[-8, -7, -257]` |
+| `resident_key` | `"discouraged" \| "preferred" \| "required"` | Whether the credential gest stored on the authenticator device. | `required` |
+| `user_verification` | `"discouraged" \| "preferred" \| "required"` | Whether user verification (like `PIN` or biometrics) is necessary. | `preferred` |
+| `display_name` | `str` | The display name of the user. | The user's `email` property |
-:::
@@ -283,11 +390,68 @@ At the moment there is no support for using passkeys authentication in the Go SD
-:::caution
+```python
+from supertokens_python import init, InputAppInfo, SupertokensConfig
+from supertokens_python.recipe import webauthn, session
+from typing import Dict, Any, Optional
+from typing_extensions import Unpack
+
+def override_webauthn_functions(original_implementation: webauthn.RecipeInterface):
+ original_sign_in_options = original_implementation.sign_in_options
+
+ async def sign_in_options(
+ tenant_id: str,
+ user_context: Dict[str, Any],
+ **kwargs: Unpack[webauthn.SignInOptionsKwargsInput]
+ ):
+ return await original_sign_in_options(
+ tenant_id=tenant_id,
+ user_context=user_context,
+ timeout=10 * 1000,
+ user_verification="required",
+ relying_party_id='example.com',
+ origin='https://example.com',
+ )
+
+ original_implementation.sign_in_options = sign_in_options
+ return original_implementation
+
+init(
+ app_info=InputAppInfo(
+ app_name="",
+ api_domain="",
+ website_domain="",
+ api_base_path="/auth",
+ website_base_path="/auth"
+ ),
+ supertokens_config=SupertokensConfig(
+ # https://try.supertokens.com is for demo purposes. Replace this with the address of your core instance (sign up on supertokens.com), or self host a core.
+ connection_uri="https://try.supertokens.com",
+ # api_key=""
+ ),
+ framework='flask', # Replace this with the framework you are using
+ recipe_list=[
+ webauthn.init(
+ config=webauthn.WebauthnConfig(
+ override=webauthn.OverrideConfig(
+ functions=override_webauthn_functions
+ )
+ )
+ ),
+ session.init() # initializes session features
+ ]
+)
+```
-At the moment there is no support for using passkeys authentication in the Python SDK.
+#### Input properties
-:::
+| Name | Type | Description | Default |
+|----------|----------|-------------|---------|
+| `relying_party_id` | `str` | The domain name of your application that the system uses for validating the credential. | Uses `get_relying_party_id` from the recipe configuration which defaults to the `api_domain` |
+| `relying_party_name` | `str` | The human-readable name of your application. | Uses `get_relying_party_name` from the recipe configuration which defaults to the `app_name` |
+| `origin` | `str` | The origin URL where the credential is generated. | Uses `get_origin` from the recipe configuration which defaults to the origin of the request |
+| `timeout` | `int` | The time in milliseconds that the user has to complete the credential validation process. | `6000` |
+| `user_verification` | `"discouraged" \| "preferred" \| "required"` | The parameter controls whether user verification (like `PIN` or biometrics) is necessary. | `preferred` |
diff --git a/docs/authentication/passkeys/initial-setup.mdx b/docs/authentication/passkeys/initial-setup.mdx
index a81c825c7..2beb9a7a9 100644
--- a/docs/authentication/passkeys/initial-setup.mdx
+++ b/docs/authentication/passkeys/initial-setup.mdx
@@ -22,8 +22,8 @@ The tutorial creates a login flow, rendered by either the **Prebuilt UI** compon
These instructions assume that you already have gone through the main [quickstart guide](/docs/quickstart/introduction).
If you have skipped that page please follow the tutorial and return here once you're done.
-:::info Restrictions
-At the moment, the authentication method is only available in the **`Node.js SDK`**.
+:::info SDK Support
+WebAuthn (Passkeys) authentication is available in the **Node.js SDK** and **Python SDK**.
:::
@@ -739,11 +739,32 @@ At the moment there is no support for using passkeys authentication in the Go SD
-:::caution
-
-At the moment there is no support for using passkeys authentication in the Python SDK.
-
-:::
+```python
+from supertokens_python import init, InputAppInfo, SupertokensConfig
+from supertokens_python.recipe import webauthn, session
+
+init(
+ app_info=InputAppInfo(
+ app_name="",
+ api_domain="",
+ website_domain="",
+ api_base_path="/auth",
+ website_base_path="/auth"
+ ),
+ supertokens_config=SupertokensConfig(
+ # We use try.supertokens for demo purposes.
+ # At the end of the tutorial we will show you how to create
+ # your own SuperTokens core instance and then update your config.
+ connection_uri="https://try.supertokens.io",
+ # api_key=""
+ ),
+ framework='flask', # Replace this with the framework you are using
+ recipe_list=[
+ webauthn.init(),
+ session.init()
+ ]
+)
+```
From d78e555a4bce08bf19ba404117e7d2b8b9a22999 Mon Sep 17 00:00:00 2001
From: Namit Nathwani
Date: Fri, 27 Jun 2025 12:35:18 +0530
Subject: [PATCH 02/10] update: adds input properties table for Python
---
.../mfa/introduction.mdx | 4 +-
.../authentication/passkeys/customization.mdx | 37 ++++++++++++-------
2 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/docs/additional-verification/mfa/introduction.mdx b/docs/additional-verification/mfa/introduction.mdx
index 9c58047e7..0e623f929 100644
--- a/docs/additional-verification/mfa/introduction.mdx
+++ b/docs/additional-verification/mfa/introduction.mdx
@@ -4,9 +4,9 @@ title: Introduction
hide_title: true
skip_llms_txt: true
description: >-
- Implement multi-factor authentication with email, SMS, TOTP, or WebAuthn, and customize
+ Implement multi-factor authentication with email, SMS, TOTP, or WebAuthn (Passkeys), and customize
user authentication preferences.
-page_type: overview
+page_type: overview
recipe: mfa
category: multi-factor-authentication
---
diff --git a/docs/authentication/passkeys/customization.mdx b/docs/authentication/passkeys/customization.mdx
index 931dd805f..53fbdb637 100644
--- a/docs/authentication/passkeys/customization.mdx
+++ b/docs/authentication/passkeys/customization.mdx
@@ -19,19 +19,6 @@ The following page describes the options that you can change and the different s
## Backend recipe configuration
-
-The backend recipe accepts the following properties during initialization:
-
-| Option | Description | Default |
-|--------|-------------|---------|
-| `getRelyingPartyId` | Sets the domain name associated with the WebAuthn credentials. This helps ensure that only your domain uses the credentials. | The `apiDomain` value that you have set in `appConfig` |
-| `getRelyingPartyName` | Sets a human-readable name for your application. The name appears to users during the WebAuthn registration process. | The `appName` value that you have set in `appConfig` |
-| `getOrigin` | Configures the origin URL that WebAuthn credentials bind to. This should match your application's domain and protocol. | Origin of the request |
-| `emailDelivery` | Configures how the system builds and sends verification emails to users. Read the [email delivery page](/docs/platform-configuration/email-delivery) for more information. | Default email service |
-| `validateEmailAddress` | Adds custom validation logic for email addresses. | Basic email format validation |
-
-All the properties are optional.
-
@@ -73,6 +60,18 @@ supertokens.init({
});
```
+The backend recipe accepts the following properties during initialization:
+
+| Option | Description | Default |
+|--------|-------------|---------|
+| `getRelyingPartyId` | Sets the domain name associated with the WebAuthn credentials. This helps ensure that only your domain uses the credentials. | The `apiDomain` value that you have set in `appConfig` |
+| `getRelyingPartyName` | Sets a human-readable name for your application. The name appears to users during the WebAuthn registration process. | The `appName` value that you have set in `appConfig` |
+| `getOrigin` | Configures the origin URL that WebAuthn credentials bind to. This should match your application's domain and protocol. | Origin of the request |
+| `emailDelivery` | Configures how the system builds and sends verification emails to users. Read the [email delivery page](/docs/platform-configuration/email-delivery) for more information. | Default email service |
+| `validateEmailAddress` | Adds custom validation logic for email addresses. | Basic email format validation |
+
+All the properties are optional.
+
@@ -127,6 +126,18 @@ init(
)
```
+The backend recipe accepts the following properties during initialization:
+
+| Option | Description | Default |
+|--------|-------------|---------|
+| `get_relying_party_id` | Sets the domain name associated with the WebAuthn credentials. This helps ensure that only your domain uses the credentials. | The `api_domain` value that you have set in `app_config` |
+| `get_relying_party_name` | Sets a human-readable name for your application. The name appears to users during the WebAuthn registration process. | The `app_name` value that you have set in `app_config` |
+| `get_origin` | Configures the origin URL that WebAuthn credentials bind to. This should match your application's domain and protocol. | Origin of the request |
+| `email_delivery` | Configures how the system builds and sends verification emails to users. Read the [email delivery page](/docs/platform-configuration/email-delivery) for more information. | Default email service |
+| `validate_email_address` | Adds custom validation logic for email addresses. | Basic email format validation |
+
+All the properties are optional.
+
From bdcbe2dfd37a3ea989a7e116e83932e51c2f7028 Mon Sep 17 00:00:00 2001
From: Namit Nathwani
Date: Fri, 27 Jun 2025 14:49:02 +0530
Subject: [PATCH 03/10] update: Python example imports, types
---
.../authentication/passkeys/customization.mdx | 46 +++++++++++--------
1 file changed, 28 insertions(+), 18 deletions(-)
diff --git a/docs/authentication/passkeys/customization.mdx b/docs/authentication/passkeys/customization.mdx
index 53fbdb637..ed887d9a2 100644
--- a/docs/authentication/passkeys/customization.mdx
+++ b/docs/authentication/passkeys/customization.mdx
@@ -88,15 +88,19 @@ At the moment there is no support for using passkeys authentication in the Go SD
```python
from supertokens_python import init, InputAppInfo, SupertokensConfig
+from supertokens_python.framework import BaseRequest
from supertokens_python.recipe import webauthn, session
+from supertokens_python.recipe.webauthn import WebauthnConfig
+from supertokens_python.types.base import UserContext
+from typing import Optional
-def get_origin(tenant_id: str, request, user_context):
+def get_origin(*, tenant_id: str, request: Optional[BaseRequest], user_context: UserContext):
return "https://example.com"
-def get_relying_party_id(tenant_id: str, request, user_context):
+def get_relying_party_id(*, tenant_id: str, request: Optional[BaseRequest], user_context: UserContext):
return "example.com"
-def get_relying_party_name(tenant_id: str, request, user_context):
+def get_relying_party_name(*, tenant_id: str, request: Optional[BaseRequest], user_context: UserContext):
return "example"
init(
@@ -115,7 +119,7 @@ init(
framework='flask', # Replace this with the framework you are using
recipe_list=[
webauthn.init(
- config=webauthn.WebauthnConfig(
+ config=WebauthnConfig(
get_origin=get_origin,
get_relying_party_id=get_relying_party_id,
get_relying_party_name=get_relying_party_name,
@@ -238,18 +242,21 @@ At the moment there is no support for using passkeys authentication in the Go SD
```python
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import webauthn, session
-from typing import Dict, Any, List, Optional, Union
-from typing_extensions import Unpack
+from supertokens_python.recipe.webauthn import WebauthnConfig, RecipeInterface
+from supertokens_python.recipe.webauthn.types.config import OverrideConfig
+from supertokens_python.types.base import UserContext
+from typing import Any, List, Optional, Union
-def override_webauthn_functions(original_implementation: webauthn.RecipeInterface):
+def override_webauthn_functions(original_implementation: RecipeInterface):
original_register_options = original_implementation.register_options
async def register_options(
+ *,
email: Optional[str],
recover_account_token: Optional[str],
tenant_id: str,
- user_context: Dict[str, Any],
- **kwargs: Unpack[webauthn.RegisterOptionsKwargsInput]
+ user_context: UserContext,
+ **kwargs: Any,
):
return await original_register_options(
email=email,
@@ -286,8 +293,8 @@ init(
framework='flask', # Replace this with the framework you are using
recipe_list=[
webauthn.init(
- config=webauthn.WebauthnConfig(
- override=webauthn.OverrideConfig(
+ config=WebauthnConfig(
+ override=OverrideConfig(
functions=override_webauthn_functions
)
)
@@ -404,16 +411,19 @@ At the moment there is no support for using passkeys authentication in the Go SD
```python
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import webauthn, session
-from typing import Dict, Any, Optional
-from typing_extensions import Unpack
+from supertokens_python.recipe.webauthn import WebauthnConfig, RecipeInterface
+from supertokens_python.recipe.webauthn.types.config import OverrideConfig
+from supertokens_python.types.base import UserContext
+from typing import Any, Optional
-def override_webauthn_functions(original_implementation: webauthn.RecipeInterface):
+def override_webauthn_functions(original_implementation: RecipeInterface):
original_sign_in_options = original_implementation.sign_in_options
async def sign_in_options(
+ *,
tenant_id: str,
- user_context: Dict[str, Any],
- **kwargs: Unpack[webauthn.SignInOptionsKwargsInput]
+ user_context: UserContext,
+ **kwargs: Any
):
return await original_sign_in_options(
tenant_id=tenant_id,
@@ -443,8 +453,8 @@ init(
framework='flask', # Replace this with the framework you are using
recipe_list=[
webauthn.init(
- config=webauthn.WebauthnConfig(
- override=webauthn.OverrideConfig(
+ config=WebauthnConfig(
+ override=OverrideConfig(
functions=override_webauthn_functions
)
)
From ede47fd3a7937b7f23b0df6fb9305601c6e14f8d Mon Sep 17 00:00:00 2001
From: Namit Nathwani
Date: Fri, 27 Jun 2025 16:02:44 +0530
Subject: [PATCH 04/10] lint: remove unused import
---
docs/authentication/passkeys/customization.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/authentication/passkeys/customization.mdx b/docs/authentication/passkeys/customization.mdx
index ed887d9a2..d7b794b47 100644
--- a/docs/authentication/passkeys/customization.mdx
+++ b/docs/authentication/passkeys/customization.mdx
@@ -414,7 +414,7 @@ from supertokens_python.recipe import webauthn, session
from supertokens_python.recipe.webauthn import WebauthnConfig, RecipeInterface
from supertokens_python.recipe.webauthn.types.config import OverrideConfig
from supertokens_python.types.base import UserContext
-from typing import Any, Optional
+from typing import Any
def override_webauthn_functions(original_implementation: RecipeInterface):
original_sign_in_options = original_implementation.sign_in_options
From 90242274a7cd1a6978c9bec049f1bf99fa8cf27b Mon Sep 17 00:00:00 2001
From: Namit Nathwani
Date: Fri, 27 Jun 2025 16:24:03 +0530
Subject: [PATCH 05/10] lint: fix type issues
---
docs/authentication/passkeys/customization.mdx | 11 +++++++----
docs/authentication/passkeys/initial-setup.mdx | 4 ++--
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/docs/authentication/passkeys/customization.mdx b/docs/authentication/passkeys/customization.mdx
index d7b794b47..2f5ff09c8 100644
--- a/docs/authentication/passkeys/customization.mdx
+++ b/docs/authentication/passkeys/customization.mdx
@@ -409,12 +409,14 @@ At the moment there is no support for using passkeys authentication in the Go SD
```python
-from supertokens_python import init, InputAppInfo, SupertokensConfig
-from supertokens_python.recipe import webauthn, session
-from supertokens_python.recipe.webauthn import WebauthnConfig, RecipeInterface
+from typing import Any
+
+from supertokens_python import InputAppInfo, SupertokensConfig, init
+from supertokens_python.recipe import session, webauthn
+from supertokens_python.recipe.webauthn import RecipeInterface, WebauthnConfig
from supertokens_python.recipe.webauthn.types.config import OverrideConfig
from supertokens_python.types.base import UserContext
-from typing import Any
+
def override_webauthn_functions(original_implementation: RecipeInterface):
original_sign_in_options = original_implementation.sign_in_options
@@ -431,6 +433,7 @@ def override_webauthn_functions(original_implementation: RecipeInterface):
timeout=10 * 1000,
user_verification="required",
relying_party_id='example.com',
+ relying_party_name='Example',
origin='https://example.com',
)
diff --git a/docs/authentication/passkeys/initial-setup.mdx b/docs/authentication/passkeys/initial-setup.mdx
index 2beb9a7a9..0bcc43cc6 100644
--- a/docs/authentication/passkeys/initial-setup.mdx
+++ b/docs/authentication/passkeys/initial-setup.mdx
@@ -740,8 +740,8 @@ At the moment there is no support for using passkeys authentication in the Go SD
```python
-from supertokens_python import init, InputAppInfo, SupertokensConfig
-from supertokens_python.recipe import webauthn, session
+from supertokens_python import InputAppInfo, SupertokensConfig, init
+from supertokens_python.recipe import session, webauthn
init(
app_info=InputAppInfo(
From 357edbd72e5feef6eafd1dc376e8b222cc74ced3 Mon Sep 17 00:00:00 2001
From: Namit Nathwani
Date: Fri, 27 Jun 2025 16:38:28 +0530
Subject: [PATCH 06/10] update: python deps
---
scripts/code-type-checking/python/requirements.txt | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/scripts/code-type-checking/python/requirements.txt b/scripts/code-type-checking/python/requirements.txt
index 8a8aa7dde..8ce6deb36 100644
--- a/scripts/code-type-checking/python/requirements.txt
+++ b/scripts/code-type-checking/python/requirements.txt
@@ -22,7 +22,7 @@ django-cors-headers==3.11.0
django-stubs==1.9.0
django-stubs-ext==0.4.0
exceptiongroup==1.1.3
-fastapi==0.68.1
+fastapi==0.115.5
filelock==3.12.2
Flask==2.0.2
Flask-Cors==3.0.10
@@ -60,11 +60,11 @@ py==1.11.0
pycodestyle==2.8.0
pycparser==2.21
pycryptodome==3.10.4
-pydantic==1.9.0
+pydantic==2.10.6
PyJWT==2.8.0
pylint==2.12.2
pyparsing==3.0.7
-pyright==1.1.236
+pyright==1.1.393
pyrsistent==0.18.1
pytest==6.2.5
pytest-asyncio==0.14.0
@@ -79,15 +79,15 @@ rfc3986==1.5.0
six==1.16.0
sniffio==1.3.0
sqlparse==0.4.2
-starlette==0.14.2
-supertokens_python==0.27.0
+starlette==0.41.3
+supertokens_python==0.30.0
tldextract==3.1.0
toml==0.10.2
tomli==2.0.1
twilio==7.9.1
types-pytz==2021.3.6
types-PyYAML==6.0.5
-typing_extensions==4.7.1
+typing_extensions==4.12.2
tzdata==2021.5
urllib3==2.0.4
uvicorn==0.18.2
From e859a83d46dcec3493aca73a9e6ccab64c97103b Mon Sep 17 00:00:00 2001
From: Namit Nathwani
Date: Fri, 27 Jun 2025 18:45:56 +0530
Subject: [PATCH 07/10] fix: pyright errors
---
.../mfa/protect-routes.mdx | 42 ++--
.../mfa/step-up-auth.mdx | 66 ++++--
.../protect-api-routes.mdx | 217 ++++++++++++------
3 files changed, 208 insertions(+), 117 deletions(-)
diff --git a/docs/additional-verification/mfa/protect-routes.mdx b/docs/additional-verification/mfa/protect-routes.mdx
index 652db4494..d1775acf7 100644
--- a/docs/additional-verification/mfa/protect-routes.mdx
+++ b/docs/additional-verification/mfa/protect-routes.mdx
@@ -367,7 +367,7 @@ async def like_comment(request: HttpRequest):
The same modification can be done for `getSession` as well.
-### Check MFA claim manually
+### Check MFA claim manually
To account for a more complex logic when you check the MFA claim (other than checking if `v` is `true`), look over the next code snippet.
@@ -869,15 +869,16 @@ At the moment this feature is not supported through the Go SDK.
```python
from fastapi import Depends
-from supertokens_python.recipe.session.framework.fastapi import verify_session
-from supertokens_python.recipe.session.exceptions import (
- raise_invalid_claims_exception,
- ClaimValidationError,
-)
-from supertokens_python.recipe.session import SessionContainer
+
from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import (
MultiFactorAuthClaim,
)
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.exceptions import (
+ ClaimValidationError,
+ raise_invalid_claims_exception,
+)
+from supertokens_python.recipe.session.framework.fastapi import verify_session
@app.post("/update-blog") # type: ignore
@@ -915,10 +916,16 @@ async def update_blog_api(session: SessionContainer = Depends(verify_session()))
```python
from flask import Flask, g
-from supertokens_python.recipe.session.framework.flask import verify_session
+
+from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import (
+ MultiFactorAuthClaim,
+)
from supertokens_python.recipe.session import SessionContainer
-from supertokens_python.recipe.session.exceptions import raise_invalid_claims_exception, ClaimValidationError
-from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import MultiFactorAuthClaim
+from supertokens_python.recipe.session.exceptions import (
+ ClaimValidationError,
+ raise_invalid_claims_exception,
+)
+from supertokens_python.recipe.session.framework.flask import verify_session
app = Flask(__name__)
@@ -952,21 +959,24 @@ def check_mfa_api():
```python
+from typing import cast
+
from django.http import HttpRequest
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+
+from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import (
+ MultiFactorAuthClaim,
+)
from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.exceptions import (
- raise_invalid_claims_exception,
ClaimValidationError,
+ raise_invalid_claims_exception,
)
-from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import (
- MultiFactorAuthClaim,
-)
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
@verify_session()
async def get_user_info_api(request: HttpRequest):
- session: SessionContainer = request.supertokens # type: ignore
+ session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore
# highlight-start
mfa_claim_value = await session.get_claim_value(MultiFactorAuthClaim)
if mfa_claim_value is None:
diff --git a/docs/additional-verification/mfa/step-up-auth.mdx b/docs/additional-verification/mfa/step-up-auth.mdx
index cebb502ef..3b2da1518 100644
--- a/docs/additional-verification/mfa/step-up-auth.mdx
+++ b/docs/additional-verification/mfa/step-up-auth.mdx
@@ -420,17 +420,19 @@ At the moment this feature is not supported through the Go SDK.
```python
+import time
+
from fastapi import Depends
-from supertokens_python.recipe.session.framework.fastapi import verify_session
-from supertokens_python.recipe.session.exceptions import (
- raise_invalid_claims_exception,
- ClaimValidationError,
-)
-from supertokens_python.recipe.session import SessionContainer
+
from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import (
MultiFactorAuthClaim,
)
-import time
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.exceptions import (
+ ClaimValidationError,
+ raise_invalid_claims_exception,
+)
+from supertokens_python.recipe.session.framework.fastapi import verify_session
@app.post("/update-blog") # type: ignore
@@ -462,12 +464,19 @@ async def update_blog_api(session: SessionContainer = Depends(verify_session()))
```python
+import time
+
from flask import Flask, g
-from supertokens_python.recipe.session.framework.flask import verify_session
+
+from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import (
+ MultiFactorAuthClaim,
+)
from supertokens_python.recipe.session import SessionContainer
-from supertokens_python.recipe.session.exceptions import raise_invalid_claims_exception, ClaimValidationError
-from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import MultiFactorAuthClaim
-import time
+from supertokens_python.recipe.session.exceptions import (
+ ClaimValidationError,
+ raise_invalid_claims_exception,
+)
+from supertokens_python.recipe.session.framework.flask import verify_session
app = Flask(__name__)
@@ -502,22 +511,25 @@ def check_mfa_api():
```python
+import time
+from typing import cast
+
from django.http import HttpRequest
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+
+from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import (
+ MultiFactorAuthClaim,
+)
from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.exceptions import (
- raise_invalid_claims_exception,
ClaimValidationError,
+ raise_invalid_claims_exception,
)
-from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import (
- MultiFactorAuthClaim,
-)
-import time
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
@verify_session()
async def get_user_info_api(request: HttpRequest):
- session: SessionContainer = request.supertokens # type: ignore
+ session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore
# highlight-start
mfa_claim_value = await session.get_claim_value(MultiFactorAuthClaim)
assert mfa_claim_value is not None
@@ -639,20 +651,24 @@ At the moment this feature is not supported through the Go SDK.
```python
-from supertokens_python import init, InputAppInfo, SupertokensConfig
+import time
+from typing import Any, Awaitable, Callable, Dict, List
+
+from supertokens_python import InputAppInfo, SupertokensConfig, init
from supertokens_python.recipe import multifactorauth
-from supertokens_python.recipe.multifactorauth.types import FactorIds, OverrideConfig
from supertokens_python.recipe.multifactorauth.interfaces import RecipeInterface
-from typing import Dict, Any, Callable, Awaitable, List
-from supertokens_python.recipe.session import SessionContainer
-from supertokens_python.recipe.multifactorauth.types import MFARequirementList
from supertokens_python.recipe.multifactorauth.multi_factor_auth_claim import (
MultiFactorAuthClaim,
)
-import time
+from supertokens_python.recipe.multifactorauth.types import (
+ FactorIds,
+ MFARequirementList,
+ OverrideConfig,
+)
+from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.exceptions import (
- raise_invalid_claims_exception,
ClaimValidationError,
+ raise_invalid_claims_exception,
)
diff --git a/docs/additional-verification/session-verification/protect-api-routes.mdx b/docs/additional-verification/session-verification/protect-api-routes.mdx
index 0aa952720..f3687c44b 100644
--- a/docs/additional-verification/session-verification/protect-api-routes.mdx
+++ b/docs/additional-verification/session-verification/protect-api-routes.mdx
@@ -384,10 +384,12 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.framework.fastapi import verify_session
-from supertokens_python.recipe.session import SessionContainer
from fastapi import Depends
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.fastapi import verify_session
+
+
# highlight-start
@app.post('/like_comment') # type: ignore
async def like_comment(session: SessionContainer = Depends(verify_session())):
@@ -401,10 +403,12 @@ async def like_comment(session: SessionContainer = Depends(verify_session())):
```python
-from supertokens_python.recipe.session.framework.flask import verify_session
-from supertokens_python.recipe.session import SessionContainer
from flask import g
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.flask import verify_session
+
+
# highlight-start
@app.route('/update-jwt', methods=['POST']) # type: ignore
@verify_session()
@@ -421,18 +425,22 @@ def like_comment():
```python
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+from typing import cast
+
from django.http import HttpRequest
+
from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+
# highlight-start
@verify_session()
async def like_comment(request: HttpRequest):
- session: SessionContainer = request.supertokens # type: ignore
+ session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore
user_id = session.get_user_id()
# highlight-end
-
+
print(user_id)
```
@@ -863,18 +871,26 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.framework.fastapi import verify_session
+from typing import Optional
+
from fastapi import Depends
+
from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.fastapi import verify_session
+
# highlight-start
-@app.post('/like_comment') # type: ignore
-async def like_comment(session: SessionContainer = Depends(verify_session(session_required=False))):
+@app.post("/like_comment") # type: ignore
+async def like_comment(
+ session: Optional[SessionContainer] = Depends(
+ verify_session(session_required=False)
+ ),
+):
if session is not None:
user_id = session.get_user_id()
- print(user_id) # TODO..
+ print(user_id) # TODO..
else:
- pass # user is not logged in
+ pass # user is not logged in
# highlight-end
```
@@ -882,11 +898,14 @@ async def like_comment(session: SessionContainer = Depends(verify_session(sessio
```python
-from supertokens_python.recipe.session.framework.flask import verify_session
-from supertokens_python.recipe.session import SessionContainer
from typing import Union
+
from flask import g
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.flask import verify_session
+
+
# highlight-start
@app.route('/update-jwt', methods=['POST']) # type: ignore
@verify_session(session_required=False)
@@ -905,16 +924,19 @@ def like_comment():
```python
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+from typing import Optional, cast
+
from django.http import HttpRequest
+
from supertokens_python.recipe.session import SessionContainer
-from typing import Union
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+
# highlight-start
@verify_session(session_required=False)
async def like_comment(request: HttpRequest):
- session: Union[None, SessionContainer] = request.supertokens # type: ignore
-
+ session: Optional[SessionContainer] = cast(Optional[SessionContainer], request.supertokens) # type: ignore
+
if session is not None:
user_id = session.get_user_id()
print(user_id) # TODO..
@@ -1346,10 +1368,12 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) {
```python
+from fastapi import Depends
+
+from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.framework.fastapi import verify_session
from supertokens_python.recipe.userroles import UserRoleClaim
-from supertokens_python.recipe.session import SessionContainer
-from fastapi import Depends
+
@app.post('/like_comment') # type: ignore
async def like_comment(session: SessionContainer = Depends(
@@ -1372,6 +1396,7 @@ async def like_comment(session: SessionContainer = Depends(
from supertokens_python.recipe.session.framework.flask import verify_session
from supertokens_python.recipe.userroles import UserRoleClaim
+
@app.route('/update-jwt', methods=['POST']) # type: ignore
@verify_session(
# highlight-start
@@ -1389,10 +1414,12 @@ def like_comment():
```python
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
from django.http import HttpRequest
+
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
from supertokens_python.recipe.userroles import UserRoleClaim
+
@verify_session(
# highlight-start
# We add the UserRoleClaim's includes validator
@@ -1672,9 +1699,11 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.asyncio import get_session
from fastapi.requests import Request
+from supertokens_python.recipe.session.asyncio import get_session
+
+
@app.post('/like-comment') # type: ignore
async def like_comment(request: Request):
# highlight-next-line
@@ -1693,30 +1722,35 @@ async def like_comment(request: Request):
```python
-from supertokens_python.recipe.session.syncio import get_session
-from flask.wrappers import Request
+from fastapi.requests import Request
-@app.route('/like-comment', methods=['POST']) # type: ignore
-def like_comment(request: Request):
+from supertokens_python.recipe.session.asyncio import get_session
+
+
+@app.post("/like-comment") # type: ignore
+async def like_comment(request: Request):
# highlight-next-line
- session = get_session(request)
+ session = await get_session(request)
if session is None:
raise Exception("Should never come here")
user_id = session.get_user_id()
- print(user_id)
+ print(user_id)
# TODO
+
```
```python
-from supertokens_python.recipe.session.asyncio import get_session
from django.http import HttpRequest
+from supertokens_python.recipe.session.asyncio import get_session
+
+
async def like_comment(request: HttpRequest):
# highlight-next-line
session = await get_session(request)
@@ -1725,7 +1759,8 @@ async def like_comment(request: HttpRequest):
user_id = session.get_user_id()
- print(user_id) # TODO
+ print(user_id) # TODO
+
```
@@ -2025,38 +2060,44 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.asyncio import get_session
from fastapi import Request
-@app.post('/like-comment') # type: ignore
+from supertokens_python.recipe.session.asyncio import get_session
+
+
+@app.post("/like-comment") # type: ignore
async def like_comment(request: Request):
# highlight-next-line
session = await get_session(request, session_required=False)
if session is not None:
user_id = session.get_user_id()
- print(user_id) # TODO:
+ print(user_id) # TODO:
else:
- pass # user is not logged in
+ pass # user is not logged in
+
```
```python
-from supertokens_python.recipe.session.syncio import get_session
from flask.wrappers import Request
-@app.route('/like-comment', methods=['POST']) # type: ignore
+from supertokens_python.recipe.session.syncio import get_session
+
+
+@app.route("/like-comment", methods=["POST"]) # type: ignore
def like_comment(request: Request):
# highlight-next-line
session = get_session(request, session_required=False)
if session is not None:
user_id = session.get_user_id()
- print(user_id) # TODO..
+ print(user_id) # TODO..
else:
- pass # user is not logged in
+ pass # user is not logged in
+
```
@@ -2064,17 +2105,20 @@ def like_comment(request: Request):
```python
from django.http import HttpRequest
+
from supertokens_python.recipe.session.asyncio import get_session
+
async def like_comment(request: HttpRequest):
# highlight-next-line
session = await get_session(request, session_required=False)
if session is not None:
user_id = session.get_user_id()
- print(user_id) # TODO..
+ print(user_id) # TODO..
else:
- pass # user is not logged in
+ pass # user is not logged in
+
```
@@ -2410,10 +2454,12 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.asyncio import get_session
from fastapi.requests import Request
+
+from supertokens_python.recipe.session.asyncio import get_session
from supertokens_python.recipe.userroles import UserRoleClaim
+
@app.post('/like-comment') # type: ignore
async def like_comment(request: Request):
session = await get_session(request,
@@ -2433,43 +2479,55 @@ async def like_comment(request: Request):
```python
-from supertokens_python.recipe.session.syncio import get_session
from flask.wrappers import Request
+
+from supertokens_python.recipe.session.syncio import get_session
from supertokens_python.recipe.userroles import UserRoleClaim
-@app.route('/like-comment', methods=['POST']) # type: ignore
+
+@app.route("/like-comment", methods=["POST"]) # type: ignore
def like_comment(request: Request):
- session = get_session(request,
- override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \
- [UserRoleClaim.validators.includes("admin")])
+ session = get_session(
+ request,
+ override_global_claim_validators=lambda global_validators,
+ session,
+ user_context: global_validators + [UserRoleClaim.validators.includes("admin")],
+ )
if session is None:
raise Exception("Should never come here")
user_id = session.get_user_id()
- print(user_id)
+ print(user_id)
# TODO
+
```
```python
-from supertokens_python.recipe.session.asyncio import get_session
from django.http import HttpRequest
+
+from supertokens_python.recipe.session.asyncio import get_session
from supertokens_python.recipe.userroles import UserRoleClaim
+
async def like_comment(request: HttpRequest):
- session = await get_session(request,
- override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \
- [UserRoleClaim.validators.includes("admin")])
+ session = await get_session(
+ request,
+ override_global_claim_validators=lambda global_validators,
+ session,
+ user_context: global_validators + [UserRoleClaim.validators.includes("admin")],
+ )
if session is None:
raise Exception("Should never come here")
user_id = session.get_user_id()
- print(user_id) # TODO
+ print(user_id) # TODO
+
```
@@ -2600,18 +2658,18 @@ The `SuperTokens.ErrorHandler` sends a `401` reply to the frontend if the `getSe
```python
from functools import wraps
-from typing import Any, Callable, Dict, TypeVar, Union, cast, List, Optional
+from typing import Any, Callable, Dict, List, Optional, TypeVar, Union, cast
from supertokens_python.framework.flask.flask_request import FlaskRequest
-from supertokens_python.recipe.session.syncio import get_session
from supertokens_python.recipe.session import SessionContainer
-from supertokens_python.recipe.session.interfaces import SessionClaimValidator
-from supertokens_python.types import MaybeAwaitable
from supertokens_python.recipe.session.exceptions import (
- UnauthorisedError,
InvalidClaimsError,
- TryRefreshTokenError
+ TryRefreshTokenError,
+ UnauthorisedError,
)
+from supertokens_python.recipe.session.interfaces import SessionClaimValidator
+from supertokens_python.recipe.session.syncio import get_session
+from supertokens_python.types import MaybeAwaitable
_T = TypeVar("_T", bound=Callable[..., Any])
@@ -2627,7 +2685,6 @@ def verify_session(
]
] = None,
) -> Callable[[_T], _T]:
-
def session_verify(f: _T) -> _T:
@wraps(f)
def wrapped_function(*args: Any, **kwargs: Any):
@@ -2635,11 +2692,13 @@ def verify_session(
baseRequest = FlaskRequest(request)
try:
- session = get_session(baseRequest,
- session_required,
- anti_csrf_check,
- check_database,
- override_global_claim_validators)
+ session = get_session(
+ baseRequest,
+ session_required,
+ anti_csrf_check,
+ check_database,
+ override_global_claim_validators,
+ )
except Exception as e:
if isinstance(e, TryRefreshTokenError):
# This means that the session exists, but the access token
@@ -2674,6 +2733,7 @@ def verify_session(
return cast(_T, wrapped_function)
return session_verify
+
```
If `get_session` throws an error (in case the input access token is invalid or has expired), then the SuperTokens middleware added to your app handles that exception. It sends a `401` to the frontend.
@@ -2801,17 +2861,19 @@ func VerifySession(accessToken string, antiCsrfToken *string, options *sessmodel
```python
-from typing import Any, Callable, Dict, TypeVar, List, Optional
+from typing import Any, Callable, Dict, List, Optional, TypeVar
-from supertokens_python.recipe.session.syncio import get_session_without_request_response
from supertokens_python.recipe.session import SessionContainer
-from supertokens_python.recipe.session.interfaces import SessionClaimValidator
-from supertokens_python.types import MaybeAwaitable
from supertokens_python.recipe.session.exceptions import (
- UnauthorisedError,
InvalidClaimsError,
- TryRefreshTokenError
+ TryRefreshTokenError,
+ UnauthorisedError,
+)
+from supertokens_python.recipe.session.interfaces import SessionClaimValidator
+from supertokens_python.recipe.session.syncio import (
+ get_session_without_request_response,
)
+from supertokens_python.types import MaybeAwaitable
_T = TypeVar("_T", bound=Callable[..., Any])
@@ -2830,12 +2892,14 @@ def verify_session(
] = None,
):
try:
- session = get_session_without_request_response(access_token,
- anti_csrf_token,
- anti_csrf_check,
- session_required,
- check_database,
- override_global_claim_validators)
+ session = get_session_without_request_response(
+ access_token,
+ anti_csrf_token,
+ anti_csrf_check,
+ session_required,
+ check_database,
+ override_global_claim_validators,
+ )
except Exception as e:
if isinstance(e, TryRefreshTokenError):
# This means that the session exists, but the access token
@@ -2872,6 +2936,7 @@ def verify_session(
if tokens["antiCsrfToken"] is not None:
# TODO: set anti-csrf token update in response via tokens["antiCsrfToken"]
pass
+
```
From 3bb9085f7eace8b8fbef7cb8ae0dc03b33d4fff1 Mon Sep 17 00:00:00 2001
From: Namit Nathwani
Date: Fri, 27 Jun 2025 19:20:45 +0530
Subject: [PATCH 08/10] fix: pyright errors
---
.../user-roles/protecting-routes.mdx | 63 +++++++---
.../implement-username-login.mdx | 87 ++++++++------
docs/authentication/m2m/legacy-flow.mdx | 14 ++-
.../authentication/passkeys/customization.mdx | 79 +++++++-----
.../passwordless/allow-list-flow.mdx | 20 ++--
.../passwordless/invite-link-flow.mdx | 32 +++--
.../ep-migration-without-password-hash.mdx | 112 ++++++++++--------
.../access-session-data.mdx | 46 ++++---
8 files changed, 277 insertions(+), 176 deletions(-)
diff --git a/docs/additional-verification/user-roles/protecting-routes.mdx b/docs/additional-verification/user-roles/protecting-routes.mdx
index 649552147..51bda315a 100644
--- a/docs/additional-verification/user-roles/protecting-routes.mdx
+++ b/docs/additional-verification/user-roles/protecting-routes.mdx
@@ -447,10 +447,12 @@ func exampleAPI(w http.ResponseWriter, r *http.Request) {
```python
+from fastapi import Depends
+
+from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.framework.fastapi import verify_session
from supertokens_python.recipe.userroles import UserRoleClaim
-from supertokens_python.recipe.session import SessionContainer
-from fastapi import Depends
+
@app.post('/like_comment') # type: ignore
async def like_comment(session: SessionContainer = Depends(
@@ -473,6 +475,7 @@ async def like_comment(session: SessionContainer = Depends(
from supertokens_python.recipe.session.framework.flask import verify_session
from supertokens_python.recipe.userroles import UserRoleClaim
+
@app.route('/update-jwt', methods=['POST']) # type: ignore
@verify_session(
# highlight-start
@@ -490,10 +493,12 @@ def like_comment():
```python
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
from django.http import HttpRequest
+
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
from supertokens_python.recipe.userroles import UserRoleClaim
+
@verify_session(
# highlight-start
# We add the UserRoleClaim's includes validator
@@ -1089,19 +1094,26 @@ func contains(s []interface{}, e string) bool {
```python
from fastapi import Depends
-from supertokens_python.recipe.session.framework.fastapi import verify_session
-from supertokens_python.recipe.session.exceptions import raise_invalid_claims_exception, ClaimValidationError
+
from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.exceptions import (
+ ClaimValidationError,
+ raise_invalid_claims_exception,
+)
+from supertokens_python.recipe.session.framework.fastapi import verify_session
from supertokens_python.recipe.userroles import UserRoleClaim
-@app.post('/update-blog') # type: ignore
+
+@app.post("/update-blog") # type: ignore
async def update_blog_api(session: SessionContainer = Depends(verify_session())):
# highlight-start
roles = await session.get_claim_value(UserRoleClaim)
if roles is None or "admin" not in roles:
- raise_invalid_claims_exception("User is not an admin", [
- ClaimValidationError(UserRoleClaim.key, None)])
+ raise_invalid_claims_exception(
+ "User is not an admin", [ClaimValidationError(UserRoleClaim.key, None)]
+ )
# highlight-end
+
```
@@ -1109,43 +1121,58 @@ async def update_blog_api(session: SessionContainer = Depends(verify_session()))
```python
from flask import Flask, g
-from supertokens_python.recipe.session.framework.flask import verify_session
+
from supertokens_python.recipe.session import SessionContainer
-from supertokens_python.recipe.session.exceptions import raise_invalid_claims_exception, ClaimValidationError
+from supertokens_python.recipe.session.exceptions import (
+ ClaimValidationError,
+ raise_invalid_claims_exception,
+)
+from supertokens_python.recipe.session.framework.flask import verify_session
from supertokens_python.recipe.userroles import UserRoleClaim
app = Flask(__name__)
-@app.route('/update-blog', methods=['POST']) # type: ignore
+
+@app.route("/update-blog", methods=["POST"]) # type: ignore
@verify_session()
def set_role_api():
session: SessionContainer = g.supertokens # type: ignore
# highlight-start
roles = session.sync_get_claim_value(UserRoleClaim)
if roles is None or "admin" not in roles:
- raise_invalid_claims_exception("User is not an admin", [
- ClaimValidationError(UserRoleClaim.key, None)])
+ raise_invalid_claims_exception(
+ "User is not an admin", [ClaimValidationError(UserRoleClaim.key, None)]
+ )
# highlight-end
+
```
```python
+from typing import cast
+
from django.http import HttpRequest
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+
from supertokens_python.recipe.session import SessionContainer
-from supertokens_python.recipe.session.exceptions import raise_invalid_claims_exception, ClaimValidationError
+from supertokens_python.recipe.session.exceptions import (
+ ClaimValidationError,
+ raise_invalid_claims_exception,
+)
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
from supertokens_python.recipe.userroles import UserRoleClaim
+
@verify_session()
async def get_user_info_api(request: HttpRequest):
- session: SessionContainer = request.supertokens # type: ignore
+ session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore
# highlight-start
roles = await session.get_claim_value(UserRoleClaim)
if roles is None or "admin" not in roles:
- raise_invalid_claims_exception("User is not an admin", [
- ClaimValidationError(UserRoleClaim.key, None)])
+ raise_invalid_claims_exception(
+ "User is not an admin", [ClaimValidationError(UserRoleClaim.key, None)]
+ )
# highlight-end
```
diff --git a/docs/authentication/email-password/implement-username-login.mdx b/docs/authentication/email-password/implement-username-login.mdx
index 32f2dce58..b3111b6d5 100644
--- a/docs/authentication/email-password/implement-username-login.mdx
+++ b/docs/authentication/email-password/implement-username-login.mdx
@@ -162,11 +162,13 @@ func main() {
```python
-from supertokens_python import init, InputAppInfo
+from re import fullmatch
+
+from supertokens_python import InputAppInfo, init
from supertokens_python.recipe import emailpassword
-from supertokens_python.recipe.emailpassword.utils import InputSignUpFeature
from supertokens_python.recipe.emailpassword.types import InputFormField
-from re import fullmatch
+from supertokens_python.recipe.emailpassword.utils import InputSignUpFeature
+
async def validate(value: str, tenant_id: str):
# first we check for if it's an email
@@ -358,13 +360,14 @@ func main() {
```python
-from supertokens_python import init, InputAppInfo
-from supertokens_python.recipe import emailpassword
-from supertokens_python.recipe.emailpassword.utils import InputSignUpFeature
-from supertokens_python.recipe.emailpassword.types import InputFormField
from re import fullmatch
from typing import Dict
+from supertokens_python import InputAppInfo, init
+from supertokens_python.recipe import emailpassword
+from supertokens_python.recipe.emailpassword.types import InputFormField
+from supertokens_python.recipe.emailpassword.utils import InputSignUpFeature
+
email_user_map: Dict[str, str] = {}
# highlight-start
@@ -578,19 +581,20 @@ func main() {
```python
-from supertokens_python import init, InputAppInfo
+from typing import Any, Dict, List, Union
+
+from supertokens_python import InputAppInfo, init
from supertokens_python.recipe import emailpassword
-from supertokens_python.recipe.emailpassword.utils import (
- InputSignUpFeature,
- InputOverrideConfig,
-)
-from supertokens_python.recipe.emailpassword.types import FormField
from supertokens_python.recipe.emailpassword.interfaces import (
APIInterface,
APIOptions,
SignUpPostOkResult,
)
-from typing import Dict, List, Union, Any
+from supertokens_python.recipe.emailpassword.types import FormField
+from supertokens_python.recipe.emailpassword.utils import (
+ InputOverrideConfig,
+ InputSignUpFeature,
+)
from supertokens_python.recipe.session.interfaces import SessionContainer
email_user_map: Dict[str, str] = {}
@@ -858,17 +862,18 @@ func main() {
```python
-from supertokens_python import init, InputAppInfo
+from re import fullmatch
+from typing import Any, Dict, Union
+
+from supertokens_python import InputAppInfo, init
+from supertokens_python.asyncio import get_user
from supertokens_python.recipe import emailpassword
+from supertokens_python.recipe.emailpassword.interfaces import RecipeInterface
from supertokens_python.recipe.emailpassword.utils import (
- InputSignUpFeature,
InputOverrideConfig,
+ InputSignUpFeature,
)
-from supertokens_python.recipe.emailpassword.interfaces import RecipeInterface
-from typing import Dict, Union, Any
-from re import fullmatch
from supertokens_python.recipe.session.interfaces import SessionContainer
-from supertokens_python.asyncio import get_user
email_user_map: Dict[str, str] = {}
@@ -1263,22 +1268,23 @@ func main() {
```python
-from supertokens_python import init, InputAppInfo
-from supertokens_python.recipe import emailpassword
+from re import fullmatch
+from typing import Any, Dict, List
+
+from supertokens_python import InputAppInfo, init
from supertokens_python.asyncio import get_user, list_users_by_account_info
-from supertokens_python.types import AccountInfo
-from supertokens_python.recipe.emailpassword.utils import (
- InputSignUpFeature,
- InputOverrideConfig,
-)
-from supertokens_python.recipe.emailpassword.types import FormField
+from supertokens_python.recipe import emailpassword
from supertokens_python.recipe.emailpassword.interfaces import (
APIInterface,
APIOptions,
)
+from supertokens_python.recipe.emailpassword.types import FormField
+from supertokens_python.recipe.emailpassword.utils import (
+ InputOverrideConfig,
+ InputSignUpFeature,
+)
from supertokens_python.types import GeneralErrorResponse
-from typing import Dict, List, Any
-from re import fullmatch
+from supertokens_python.types.base import AccountInfoInput
email_user_map: Dict[str, str] = {}
@@ -1362,7 +1368,7 @@ def apis_override(original: APIInterface):
if field.id == "email":
username = field.value
supertokens_user = await list_users_by_account_info(
- tenant_id, AccountInfo(email=username)
+ tenant_id, AccountInfoInput(email=username)
)
target_user = next(
(
@@ -1592,13 +1598,20 @@ func main() {
```python
-from supertokens_python import init, InputAppInfo
-from supertokens_python.recipe import emailpassword
-from supertokens_python.recipe.emailpassword.utils import InputSignUpFeature, InputOverrideConfig
-from supertokens_python.ingredients.emaildelivery.types import EmailDeliveryConfig
-from typing import Dict, Any
from re import fullmatch
-from supertokens_python.recipe.emailpassword.types import EmailDeliveryOverrideInput, EmailTemplateVars
+from typing import Any, Dict
+
+from supertokens_python import InputAppInfo, init
+from supertokens_python.ingredients.emaildelivery.types import EmailDeliveryConfig
+from supertokens_python.recipe import emailpassword
+from supertokens_python.recipe.emailpassword.types import (
+ EmailDeliveryOverrideInput,
+ EmailTemplateVars,
+)
+from supertokens_python.recipe.emailpassword.utils import (
+ InputOverrideConfig,
+ InputSignUpFeature,
+)
email_user_map: Dict[str, str] = {}
diff --git a/docs/authentication/m2m/legacy-flow.mdx b/docs/authentication/m2m/legacy-flow.mdx
index f40fe859a..c577d63ba 100644
--- a/docs/authentication/m2m/legacy-flow.mdx
+++ b/docs/authentication/m2m/legacy-flow.mdx
@@ -134,7 +134,7 @@ func main() {
```python
-from supertokens_python import init, InputAppInfo, SupertokensConfig
+from supertokens_python import InputAppInfo, SupertokensConfig, init
from supertokens_python.recipe import jwt
init(
@@ -218,6 +218,7 @@ func main() {
from supertokens_python.recipe.jwt import asyncio
from supertokens_python.recipe.jwt.interfaces import CreateJwtOkResult
+
async def create_jwt():
jwtResponse = await asyncio.create_jwt({
"source": "microservice",
@@ -235,8 +236,8 @@ async def create_jwt():
```python
-from supertokens_python.recipe.jwt.syncio import create_jwt
from supertokens_python.recipe.jwt.interfaces import CreateJwtOkResult
+from supertokens_python.recipe.jwt.syncio import create_jwt
jwtResponse = create_jwt({
"source": "microservice",
@@ -595,17 +596,20 @@ app.post("/like-comment", async (req, res, next) => {
```python
-from supertokens_python.recipe.session.asyncio import get_session
-from django.http import HttpRequest
from typing import Union
+from django.http import HttpRequest
+
+from supertokens_python.recipe.session.asyncio import get_session
+
+
async def like_comment(request: HttpRequest):
session = await get_session(request, session_required=False)
user_id = ""
if session is not None:
user_id = session.get_user_id()
else:
- jwt: Union[str, None] = request.headers.get("Authorization") # type: ignore
+ jwt: Union[str, None] = request.headers.get("Authorization")
if jwt is None:
# return a 401 unauthorised error...
pass
diff --git a/docs/authentication/passkeys/customization.mdx b/docs/authentication/passkeys/customization.mdx
index 2f5ff09c8..1b50691c2 100644
--- a/docs/authentication/passkeys/customization.mdx
+++ b/docs/authentication/passkeys/customization.mdx
@@ -87,20 +87,22 @@ At the moment there is no support for using passkeys authentication in the Go SD
```python
-from supertokens_python import init, InputAppInfo, SupertokensConfig
+from typing import Optional
+
+from supertokens_python import InputAppInfo, SupertokensConfig, init
from supertokens_python.framework import BaseRequest
-from supertokens_python.recipe import webauthn, session
+from supertokens_python.recipe import session, webauthn
from supertokens_python.recipe.webauthn import WebauthnConfig
from supertokens_python.types.base import UserContext
-from typing import Optional
-def get_origin(*, tenant_id: str, request: Optional[BaseRequest], user_context: UserContext):
+
+async def get_origin(*, tenant_id: str, request: Optional[BaseRequest], user_context: UserContext):
return "https://example.com"
-def get_relying_party_id(*, tenant_id: str, request: Optional[BaseRequest], user_context: UserContext):
+async def get_relying_party_id(*, tenant_id: str, request: Optional[BaseRequest], user_context: UserContext):
return "example.com"
-def get_relying_party_name(*, tenant_id: str, request: Optional[BaseRequest], user_context: UserContext):
+async def get_relying_party_name(*, tenant_id: str, user_context: UserContext):
return "example"
init(
@@ -240,68 +242,85 @@ At the moment there is no support for using passkeys authentication in the Go SD
```python
-from supertokens_python import init, InputAppInfo, SupertokensConfig
-from supertokens_python.recipe import webauthn, session
-from supertokens_python.recipe.webauthn import WebauthnConfig, RecipeInterface
+from typing import Any, List, Optional, cast
+
+from typing_extensions import Unpack
+
+from supertokens_python import InputAppInfo, SupertokensConfig, init
+from supertokens_python.recipe import session, webauthn
+from supertokens_python.recipe.webauthn import RecipeInterface, WebauthnConfig
+from supertokens_python.recipe.webauthn.interfaces.recipe import (
+ Attestation,
+ RegisterOptionsKwargsInput,
+ ResidentKey,
+ UserVerification,
+)
from supertokens_python.recipe.webauthn.types.config import OverrideConfig
from supertokens_python.types.base import UserContext
-from typing import Any, List, Optional, Union
+
def override_webauthn_functions(original_implementation: RecipeInterface):
original_register_options = original_implementation.register_options
async def register_options(
*,
- email: Optional[str],
- recover_account_token: Optional[str],
+ relying_party_id: str,
+ relying_party_name: str,
+ origin: str,
+ resident_key: Optional[ResidentKey] = None,
+ user_verification: Optional[UserVerification] = None,
+ user_presence: Optional[bool] = None,
+ attestation: Optional[Attestation] = None,
+ supported_algorithm_ids: Optional[List[int]] = None,
+ timeout: Optional[int] = None,
tenant_id: str,
user_context: UserContext,
- **kwargs: Any,
+ **kwargs: Unpack[RegisterOptionsKwargsInput],
):
return await original_register_options(
- email=email,
- recover_account_token=recover_account_token,
- tenant_id=tenant_id,
- user_context=user_context,
- attestation="direct",
+ relying_party_id="example.com",
+ relying_party_name="example",
+ origin="https://example.com",
resident_key="required",
- timeout=10 * 1000,
user_verification="required",
+ user_presence=True,
+ attestation="direct",
+ timeout=10 * 1000,
+ tenant_id=tenant_id,
+ user_context=user_context,
+ email=cast(str, kwargs.get("email")),
+ recover_account_token=cast(str, kwargs.get("recover_account_token")),
display_name="John Doe",
- supported_algorithms=[-257],
- relying_party_id='example.com',
- relying_party_name='example',
- origin='https://example.com',
)
original_implementation.register_options = register_options
return original_implementation
+
init(
app_info=InputAppInfo(
app_name="",
api_domain="",
website_domain="",
api_base_path="/auth",
- website_base_path="/auth"
+ website_base_path="/auth",
),
supertokens_config=SupertokensConfig(
# https://try.supertokens.com is for demo purposes. Replace this with the address of your core instance (sign up on supertokens.com), or self host a core.
connection_uri="https://try.supertokens.com",
# api_key=""
),
- framework='flask', # Replace this with the framework you are using
+ framework="flask", # Replace this with the framework you are using
recipe_list=[
webauthn.init(
config=WebauthnConfig(
- override=OverrideConfig(
- functions=override_webauthn_functions
- )
+ override=OverrideConfig(functions=override_webauthn_functions)
)
),
- session.init() # initializes session features
- ]
+ session.init(), # initializes session features
+ ],
)
+
```
diff --git a/docs/authentication/passwordless/allow-list-flow.mdx b/docs/authentication/passwordless/allow-list-flow.mdx
index 22dfb6172..7cdd137d2 100644
--- a/docs/authentication/passwordless/allow-list-flow.mdx
+++ b/docs/authentication/passwordless/allow-list-flow.mdx
@@ -157,9 +157,14 @@ func isPhoneNumberAllowed(phoneNumber string) (bool, error) {
```python
-from supertokens_python.recipe.usermetadata.asyncio import get_user_metadata, update_user_metadata
from typing import List
+from supertokens_python.recipe.usermetadata.asyncio import (
+ get_user_metadata,
+ update_user_metadata,
+)
+
+
async def add_email_to_allow_list(email: str):
metadataResult = await get_user_metadata("emailAllowList")
allow_list: List[str] = metadataResult.metadata["allowList"] if "allowList" in metadataResult.metadata else []
@@ -338,17 +343,18 @@ func main() {
```python
-from supertokens_python import init, InputAppInfo
-from supertokens_python.types import GeneralErrorResponse
-from supertokens_python.recipe import passwordless
+from typing import Any, Dict, Optional, Union
+
+from supertokens_python import InputAppInfo, init
from supertokens_python.asyncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo
+from supertokens_python.recipe import passwordless
from supertokens_python.recipe.passwordless.interfaces import (
APIInterface,
APIOptions,
)
-from typing import Union, Dict, Any, Optional
from supertokens_python.recipe.session.interfaces import SessionContainer
+from supertokens_python.types import AccountInfo, GeneralErrorResponse
+from supertokens_python.types.base import AccountInfoInput
async def is_email_allowed(email: str):
@@ -375,7 +381,7 @@ def override_passwordless_apis(original_implementation: APIInterface):
):
if email is not None:
existing_user = await list_users_by_account_info(
- tenant_id, AccountInfo(email=email)
+ tenant_id, AccountInfoInput(email=email)
)
user_with_passwordless = next(
(
diff --git a/docs/authentication/passwordless/invite-link-flow.mdx b/docs/authentication/passwordless/invite-link-flow.mdx
index 774f08225..8bc658542 100644
--- a/docs/authentication/passwordless/invite-link-flow.mdx
+++ b/docs/authentication/passwordless/invite-link-flow.mdx
@@ -618,11 +618,13 @@ func createUserAPI(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.framework.fastapi import verify_session
-from supertokens_python.recipe.session import SessionContainer
from fastapi import Depends
-from supertokens_python.recipe.userroles import UserRoleClaim
+
from supertokens_python.recipe.passwordless.asyncio import create_magic_link, signinup
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.fastapi import verify_session
+from supertokens_python.recipe.userroles import UserRoleClaim
+
@app.post('/create-user') # type: ignore
async def create_user(session: SessionContainer = Depends(verify_session(
@@ -645,9 +647,10 @@ async def create_user(session: SessionContainer = Depends(verify_session(
```python
+from supertokens_python.recipe.passwordless.syncio import create_magic_link, signinup
from supertokens_python.recipe.session.framework.flask import verify_session
from supertokens_python.recipe.userroles import UserRoleClaim
-from supertokens_python.recipe.passwordless.syncio import create_magic_link, signinup
+
@app.route('/create_user', methods=['POST']) # type: ignore
@verify_session(
@@ -671,10 +674,12 @@ def create_user():
```python
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
from django.http import HttpRequest
-from supertokens_python.recipe.userroles import UserRoleClaim
+
from supertokens_python.recipe.passwordless.asyncio import create_magic_link, signinup
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+from supertokens_python.recipe.userroles import UserRoleClaim
+
@verify_session(
override_global_claim_validators=lambda global_validators, session, user_context: global_validators +
@@ -818,14 +823,15 @@ func main() {
```python
-from supertokens_python import init, InputAppInfo
-from supertokens_python.types import GeneralErrorResponse
+from typing import Any, Dict, Optional, Union
+
+from supertokens_python import InputAppInfo, init
+from supertokens_python.asyncio import list_users_by_account_info
from supertokens_python.recipe import passwordless
from supertokens_python.recipe.passwordless.interfaces import APIInterface, APIOptions
-from typing import Union, Dict, Any, Optional
from supertokens_python.recipe.session.interfaces import SessionContainer
-from supertokens_python.asyncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo
+from supertokens_python.types import GeneralErrorResponse
+from supertokens_python.types.base import AccountInfoInput
def override_passwordless_apis(original_implementation: APIInterface):
@@ -842,7 +848,7 @@ def override_passwordless_apis(original_implementation: APIInterface):
):
if email is not None:
existing_user = await list_users_by_account_info(
- tenant_id, AccountInfo(email=email)
+ tenant_id, AccountInfoInput(email=email)
)
user_with_passwordless = next(
(
@@ -862,7 +868,7 @@ def override_passwordless_apis(original_implementation: APIInterface):
else:
assert phone_number is not None
existing_user = await list_users_by_account_info(
- tenant_id, AccountInfo(phone_number=phone_number)
+ tenant_id, AccountInfoInput(phone_number=phone_number)
)
user_with_passwordless = next(
(
diff --git a/docs/migration/legacy/account-creation/ep-migration-without-password-hash.mdx b/docs/migration/legacy/account-creation/ep-migration-without-password-hash.mdx
index bedaebc6a..4bf774712 100644
--- a/docs/migration/legacy/account-creation/ep-migration-without-password-hash.mdx
+++ b/docs/migration/legacy/account-creation/ep-migration-without-password-hash.mdx
@@ -74,7 +74,9 @@ async function doesUserExistInExternalProvider(email: string): Promise
```python
-from supertokens_python import init, InputAppInfo
+from typing import Any, Dict, List, Union
+
+from supertokens_python import InputAppInfo, init
from supertokens_python.recipe import emailpassword
from supertokens_python.recipe.emailpassword.interfaces import (
APIInterface,
@@ -82,7 +84,6 @@ from supertokens_python.recipe.emailpassword.interfaces import (
EmailAlreadyExistsError,
)
from supertokens_python.recipe.emailpassword.types import FormField
-from typing import Dict, Any, Union, List
from supertokens_python.recipe.session.interfaces import SessionContainer
@@ -288,19 +289,15 @@ async function validateAndGetUserInfoFromExternalProvider(email: string, passwor
```python
-from supertokens_python import init, InputAppInfo
-from supertokens_python.recipe import emailpassword
-from supertokens_python.asyncio import create_user_id_mapping
-from supertokens_python.recipe.emailverification.asyncio import (
- create_email_verification_token,
- verify_email_using_token,
-)
-from supertokens_python.recipe.emailpassword.asyncio import sign_up
-from supertokens_python.recipe.emailverification.interfaces import (
- CreateEmailVerificationTokenOkResult,
+from typing import Any, Dict, List, Union
+
+from supertokens_python import InputAppInfo, init
+from supertokens_python.asyncio import (
+ create_user_id_mapping,
+ list_users_by_account_info,
)
-from supertokens_python import init, InputAppInfo
from supertokens_python.recipe import emailpassword
+from supertokens_python.recipe.emailpassword.asyncio import sign_up
from supertokens_python.recipe.emailpassword.interfaces import (
APIInterface,
APIOptions,
@@ -308,10 +305,16 @@ from supertokens_python.recipe.emailpassword.interfaces import (
WrongCredentialsError,
)
from supertokens_python.recipe.emailpassword.types import FormField
-from typing import Dict, Any, Union, List
+from supertokens_python.recipe.emailverification.asyncio import (
+ create_email_verification_token,
+ verify_email_using_token,
+)
+from supertokens_python.recipe.emailverification.interfaces import (
+ CreateEmailVerificationTokenOkResult,
+)
from supertokens_python.recipe.session.interfaces import SessionContainer
-from supertokens_python.asyncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo, RecipeUserId
+from supertokens_python.types import RecipeUserId
+from supertokens_python.types.base import AccountInfoInput
def override_emailpassword_apis(original_implementation: APIInterface):
@@ -334,7 +337,7 @@ def override_emailpassword_apis(original_implementation: APIInterface):
password = field.value
# Check if an email-password user with the input email exists in SuperTokens
supertokens_user_with_same_email = await list_users_by_account_info(
- tenant_id, AccountInfo(email=email), False, user_context
+ tenant_id, AccountInfoInput(email=email), False, user_context
)
emailpassword_user = next(
(
@@ -653,27 +656,31 @@ async function retrieveUserDataFromExternalProvider(email: string): Promise<{
```python
-from supertokens_python import init, InputAppInfo
-from supertokens_python.asyncio import create_user_id_mapping
-from supertokens_python.recipe import emailpassword
-from supertokens_python.asyncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo, RecipeUserId
-from supertokens_python.recipe.emailverification.asyncio import (
- create_email_verification_token,
- verify_email_using_token,
+from typing import Any, Dict, List, Union
+
+from supertokens_python import InputAppInfo, init
+from supertokens_python.asyncio import (
+ create_user_id_mapping,
+ list_users_by_account_info,
)
-from supertokens_python.recipe.emailpassword.types import FormField
+from supertokens_python.recipe import emailpassword
from supertokens_python.recipe.emailpassword.asyncio import sign_up
-from supertokens_python.recipe.usermetadata.asyncio import update_user_metadata
from supertokens_python.recipe.emailpassword.interfaces import (
APIInterface,
APIOptions,
SignUpOkResult,
)
+from supertokens_python.recipe.emailpassword.types import FormField
+from supertokens_python.recipe.emailverification.asyncio import (
+ create_email_verification_token,
+ verify_email_using_token,
+)
from supertokens_python.recipe.emailverification.interfaces import (
CreateEmailVerificationTokenOkResult,
)
-from typing import Union, Dict, Any, List
+from supertokens_python.recipe.usermetadata.asyncio import update_user_metadata
+from supertokens_python.types import RecipeUserId
+from supertokens_python.types.base import AccountInfoInput
def override_emailpassword_apis(original_implementation: APIInterface):
@@ -697,7 +704,7 @@ def override_emailpassword_apis(original_implementation: APIInterface):
# Check if an email-password user with the input email exists in SuperTokens
supertokens_user_with_same_email = await list_users_by_account_info(
- tenant_id, AccountInfo(email=email), False, user_context
+ tenant_id, AccountInfoInput(email=email), False, user_context
)
emailpassword_user = next(
(
@@ -977,19 +984,20 @@ EmailPassword.init({
```python
-from supertokens_python import init, InputAppInfo
+from typing import Any, Dict, List
+
+from supertokens_python import InputAppInfo, init
from supertokens_python.recipe import emailpassword
-from supertokens_python.recipe.emailpassword.types import FormField
-from supertokens_python.recipe.usermetadata.asyncio import (
- get_user_metadata,
- update_user_metadata,
-)
from supertokens_python.recipe.emailpassword.interfaces import (
APIInterface,
APIOptions,
PasswordResetPostOkResult,
)
-from typing import Dict, Any, List
+from supertokens_python.recipe.emailpassword.types import FormField
+from supertokens_python.recipe.usermetadata.asyncio import (
+ get_user_metadata,
+ update_user_metadata,
+)
def override_emailpassword_apis(original_implementation: APIInterface):
@@ -1220,22 +1228,18 @@ async function validateAndGetUserInfoFromExternalProvider(email: string, passwor
```python
-from supertokens_python import init, InputAppInfo
-from supertokens_python.recipe import emailpassword
-from supertokens_python.asyncio import create_user_id_mapping
-from supertokens_python.recipe.emailverification.asyncio import (
- create_email_verification_token,
- verify_email_using_token,
+from typing import Any, Dict, List, Union
+
+from supertokens_python import InputAppInfo, init
+from supertokens_python.asyncio import (
+ create_user_id_mapping,
+ list_users_by_account_info,
)
+from supertokens_python.recipe import emailpassword
from supertokens_python.recipe.emailpassword.asyncio import (
sign_up,
update_email_or_password,
)
-from supertokens_python.recipe.emailverification.interfaces import (
- CreateEmailVerificationTokenOkResult,
-)
-from supertokens_python import init, InputAppInfo
-from supertokens_python.recipe import emailpassword
from supertokens_python.recipe.emailpassword.interfaces import (
APIInterface,
APIOptions,
@@ -1243,14 +1247,20 @@ from supertokens_python.recipe.emailpassword.interfaces import (
WrongCredentialsError,
)
from supertokens_python.recipe.emailpassword.types import FormField
-from typing import Dict, Any, Union, List
+from supertokens_python.recipe.emailverification.asyncio import (
+ create_email_verification_token,
+ verify_email_using_token,
+)
+from supertokens_python.recipe.emailverification.interfaces import (
+ CreateEmailVerificationTokenOkResult,
+)
from supertokens_python.recipe.session.interfaces import SessionContainer
-from supertokens_python.asyncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo, RecipeUserId
from supertokens_python.recipe.usermetadata.asyncio import (
get_user_metadata,
update_user_metadata,
)
+from supertokens_python.types import RecipeUserId
+from supertokens_python.types.base import AccountInfoInput
def override_emailpassword_apis(original_implementation: APIInterface):
@@ -1273,7 +1283,7 @@ def override_emailpassword_apis(original_implementation: APIInterface):
password = field.value
# Check if an email-password user with the input email exists in SuperTokens
supertokens_user_with_same_email = await list_users_by_account_info(
- tenant_id, AccountInfo(email=email), False, user_context
+ tenant_id, AccountInfoInput(email=email), False, user_context
)
emailpassword_user = next(
(
diff --git a/docs/post-authentication/session-management/access-session-data.mdx b/docs/post-authentication/session-management/access-session-data.mdx
index ba580e513..4b92890ea 100644
--- a/docs/post-authentication/session-management/access-session-data.mdx
+++ b/docs/post-authentication/session-management/access-session-data.mdx
@@ -286,9 +286,11 @@ func getJWT(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.framework.fastapi import verify_session
from fastapi import Depends
+
from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.fastapi import verify_session
+
@app.get('/getJWT') # type: ignore
async def get_jwt(session: SessionContainer = Depends(verify_session())):
@@ -302,10 +304,12 @@ async def get_jwt(session: SessionContainer = Depends(verify_session())):
```python
-from supertokens_python.recipe.session.framework.flask import verify_session
-from supertokens_python.recipe.session import SessionContainer
from flask import g
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.flask import verify_session
+
+
@app.route('/getJWT', methods=['GET']) # type: ignore
@verify_session()
def get_jwt():
@@ -321,13 +325,17 @@ def get_jwt():
```python
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+from typing import cast
+
from django.http import HttpRequest
+
from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+
@verify_session()
async def get_jwt(request: HttpRequest):
- session: SessionContainer = request.supertokens # type: ignore
+ session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore
# highlight-next-line
current_jwt = session.get_access_token()
@@ -403,7 +411,7 @@ func main() {
```python
-from supertokens_python import init, InputAppInfo
+from supertokens_python import InputAppInfo, init
from supertokens_python.recipe import session
init(
@@ -928,26 +936,30 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.framework.fastapi import verify_session
from fastapi import Depends
+
from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.fastapi import verify_session
+
@app.get('/getTenantId') # type: ignore
async def get_tenant_id(session: SessionContainer = Depends(verify_session())):
# highlight-next-line
tenant_id = session.get_tenant_id()
- print(tenant_id)
+ print(tenant_id)
```
```python
-from supertokens_python.recipe.session.framework.flask import verify_session
-from supertokens_python.recipe.session import SessionContainer
from flask import g
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.flask import verify_session
+
+
@app.route('/getTenantId', methods=['GET']) # type: ignore
@verify_session()
def get_tenant_id():
@@ -956,25 +968,29 @@ def get_tenant_id():
# highlight-next-line
tenant_id = session.get_tenant_id()
- print(tenant_id)
+ print(tenant_id)
```
```python
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+from typing import cast
+
from django.http import HttpRequest
+
from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+
@verify_session()
async def get_tenant_id(request: HttpRequest):
- session: SessionContainer = request.supertokens # type: ignore
+ session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore
# highlight-next-line
tenant_id = session.get_tenant_id()
- print(tenant_id)
+ print(tenant_id)
```
@@ -1059,6 +1075,7 @@ func main() {
```python
from supertokens_python.recipe.session.asyncio import get_all_session_handles_for_user
+
async def some_func():
# session_handles is List[string]
# highlight-next-line
@@ -1080,7 +1097,6 @@ async def some_func():
```python
from supertokens_python.recipe.session.syncio import get_all_session_handles_for_user
-
# session_handles is List[string]
# highlight-next-line
session_handles = get_all_session_handles_for_user("someUserId")
From c8b82183c5940812a5c3c9eef5568e7c0e40a17d Mon Sep 17 00:00:00 2001
From: Namit Nathwani
Date: Fri, 27 Jun 2025 19:49:25 +0530
Subject: [PATCH 09/10] fix: pyright errors
---
docs/authentication/m2m/legacy-flow.mdx | 4 +-
.../authentication/passkeys/customization.mdx | 3 +-
.../social/custom-invite-flow.mdx | 24 ++--
.../access-token-blacklisting.mdx | 32 +++--
.../advanced-workflows/user-impersonation.mdx | 64 ++++++----
.../user-management/account-deduplication.mdx | 31 +++--
.../allow-users-to-update-their-data.mdx | 109 +++++++++---------
.../user-management/common-actions.mdx | 68 ++++++-----
docs/quickstart/backend-setup.mdx | 29 +++--
.../backend-sdks/function-overrides.mdx | 44 ++++---
10 files changed, 247 insertions(+), 161 deletions(-)
diff --git a/docs/authentication/m2m/legacy-flow.mdx b/docs/authentication/m2m/legacy-flow.mdx
index c577d63ba..59ccb7b21 100644
--- a/docs/authentication/m2m/legacy-flow.mdx
+++ b/docs/authentication/m2m/legacy-flow.mdx
@@ -596,7 +596,7 @@ app.post("/like-comment", async (req, res, next) => {
```python
-from typing import Union
+from typing import Optional, Union, cast
from django.http import HttpRequest
@@ -609,7 +609,7 @@ async def like_comment(request: HttpRequest):
if session is not None:
user_id = session.get_user_id()
else:
- jwt: Union[str, None] = request.headers.get("Authorization")
+ jwt: Optional[str] = cast(Optional[str], request.headers.get("Authorization")) # type: ignore
if jwt is None:
# return a 401 unauthorised error...
pass
diff --git a/docs/authentication/passkeys/customization.mdx b/docs/authentication/passkeys/customization.mdx
index 1b50691c2..fe0a2fc0c 100644
--- a/docs/authentication/passkeys/customization.mdx
+++ b/docs/authentication/passkeys/customization.mdx
@@ -242,7 +242,7 @@ At the moment there is no support for using passkeys authentication in the Go SD
```python
-from typing import Any, List, Optional, cast
+from typing import List, Optional, cast
from typing_extensions import Unpack
@@ -320,7 +320,6 @@ init(
session.init(), # initializes session features
],
)
-
```
diff --git a/docs/authentication/social/custom-invite-flow.mdx b/docs/authentication/social/custom-invite-flow.mdx
index f48df09b3..abf6d26cb 100644
--- a/docs/authentication/social/custom-invite-flow.mdx
+++ b/docs/authentication/social/custom-invite-flow.mdx
@@ -105,9 +105,14 @@ func isEmailAllowed(email string) (bool, error) {
```python
-from supertokens_python.recipe.usermetadata.asyncio import get_user_metadata, update_user_metadata
from typing import List
+from supertokens_python.recipe.usermetadata.asyncio import (
+ get_user_metadata,
+ update_user_metadata,
+)
+
+
async def add_email_to_allow_list(email: str):
metadataResult = await get_user_metadata("emailAllowList")
allow_list: List[str] = metadataResult.metadata["allowList"] if "allowList" in metadataResult.metadata else []
@@ -266,20 +271,21 @@ func main() {
```python
-from supertokens_python import init, InputAppInfo
-from supertokens_python.types import GeneralErrorResponse
+from typing import Any, Dict, Optional, Union
+
+from supertokens_python import InputAppInfo, init
+from supertokens_python.asyncio import list_users_by_account_info
from supertokens_python.recipe import thirdparty
+from supertokens_python.recipe.session.interfaces import SessionContainer
from supertokens_python.recipe.thirdparty.interfaces import (
APIInterface,
- RecipeInterface,
APIOptions,
+ RecipeInterface,
)
-from typing import Optional, Dict, Any, Union
-from supertokens_python.asyncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo
from supertokens_python.recipe.thirdparty.provider import Provider, RedirectUriInfo
from supertokens_python.recipe.thirdparty.types import RawUserInfoFromProvider
-from supertokens_python.recipe.session.interfaces import SessionContainer
+from supertokens_python.types import GeneralErrorResponse
+from supertokens_python.types.base import AccountInfoInput
async def is_email_allowed(email: str):
@@ -303,7 +309,7 @@ def override_thirdparty_functions(original_implementation: RecipeInterface):
user_context: Dict[str, Any],
):
existing_users = await list_users_by_account_info(
- tenant_id, AccountInfo(email=email)
+ tenant_id, AccountInfoInput(email=email)
)
if len(existing_users) == 0:
if not await is_email_allowed(email):
diff --git a/docs/post-authentication/session-management/advanced-workflows/access-token-blacklisting.mdx b/docs/post-authentication/session-management/advanced-workflows/access-token-blacklisting.mdx
index f3ed0af08..e5fe2711f 100644
--- a/docs/post-authentication/session-management/advanced-workflows/access-token-blacklisting.mdx
+++ b/docs/post-authentication/session-management/advanced-workflows/access-token-blacklisting.mdx
@@ -396,10 +396,12 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.framework.fastapi import verify_session
-from supertokens_python.recipe.session import SessionContainer
from fastapi import Depends
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.fastapi import verify_session
+
+
# highlight-start
@app.post('/like_comment') # type: ignore
async def like_comment(session: SessionContainer = Depends(verify_session(check_database=True))):
@@ -413,10 +415,12 @@ async def like_comment(session: SessionContainer = Depends(verify_session(check_
```python
-from supertokens_python.recipe.session.framework.flask import verify_session
-from supertokens_python.recipe.session import SessionContainer
from flask import g
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.flask import verify_session
+
+
# highlight-start
@app.route('/update-jwt', methods=['POST']) # type: ignore
@verify_session(check_database=True)
@@ -433,18 +437,22 @@ def like_comment():
```python
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+from typing import cast
+
from django.http import HttpRequest
+
from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+
# highlight-start
@verify_session(check_database=True)
async def like_comment(request: HttpRequest):
- session: SessionContainer = request.supertokens # type: ignore
+ session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore
user_id = session.get_user_id()
# highlight-end
-
+
print(user_id)
```
@@ -734,9 +742,11 @@ func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.asyncio import get_session
from fastapi import Request
+from supertokens_python.recipe.session.asyncio import get_session
+
+
@app.post('/like-comment') # type: ignore
async def like_comment(request: Request):
# highlight-next-line
@@ -753,9 +763,11 @@ async def like_comment(request: Request):
```python
-from supertokens_python.recipe.session.syncio import get_session
from flask.wrappers import Request
+from supertokens_python.recipe.session.syncio import get_session
+
+
@app.route('/like-comment', methods=['POST']) # type: ignore
def like_comment(request: Request):
# highlight-next-line
@@ -773,8 +785,10 @@ def like_comment(request: Request):
```python
from django.http import HttpRequest
+
from supertokens_python.recipe.session.asyncio import get_session
+
async def like_comment(request: HttpRequest):
# highlight-next-line
session = await get_session(request, check_database=True)
diff --git a/docs/post-authentication/session-management/advanced-workflows/user-impersonation.mdx b/docs/post-authentication/session-management/advanced-workflows/user-impersonation.mdx
index 376552e25..e2510465c 100644
--- a/docs/post-authentication/session-management/advanced-workflows/user-impersonation.mdx
+++ b/docs/post-authentication/session-management/advanced-workflows/user-impersonation.mdx
@@ -488,15 +488,15 @@ func impersonate(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.framework.fastapi import verify_session
-from supertokens_python.recipe.session.asyncio import create_new_session
+from fastapi import Depends, Request
from fastapi.responses import JSONResponse
+
+from supertokens_python.asyncio import list_users_by_account_info
from supertokens_python.recipe.session import SessionContainer
-from fastapi import Depends
+from supertokens_python.recipe.session.asyncio import create_new_session
+from supertokens_python.recipe.session.framework.fastapi import verify_session
from supertokens_python.recipe.userroles import UserRoleClaim
-from supertokens_python.asyncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo
-from fastapi import Request
+from supertokens_python.types.base import AccountInfoInput
@app.post("/impersonate") # type: ignore
@@ -505,7 +505,9 @@ async def impersonate(
session: SessionContainer = Depends(
verify_session(
# We add the UserRoleClaim's includes validator
- override_global_claim_validators=lambda global_validators, session, user_context: global_validators
+ override_global_claim_validators=lambda global_validators,
+ session,
+ user_context: global_validators
+ [UserRoleClaim.validators.includes("admin")]
)
),
@@ -513,7 +515,7 @@ async def impersonate(
email = "..." # get from request body
# we use the email password recipe here, but you can use the recipe you use
- user = await list_users_by_account_info("public", AccountInfo(email=email))
+ user = await list_users_by_account_info("public", AccountInfoInput(email=email))
if len(user) == 0:
# return a 400 error to the client
@@ -534,64 +536,82 @@ async def impersonate(
```python
-from supertokens_python.recipe.session.syncio import create_new_session
from flask import jsonify
from flask.wrappers import Request
+
from supertokens_python.recipe.session.framework.flask import verify_session
+from supertokens_python.recipe.session.syncio import create_new_session
from supertokens_python.recipe.userroles import UserRoleClaim
from supertokens_python.syncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo
+from supertokens_python.types.base import AccountInfoInput
+
@app.route("/impersonate", methods=["POST"]) # type: ignore
@verify_session(
# We add the UserRoleClaim's includes validator
- override_global_claim_validators=lambda global_validators, session, user_context: global_validators
- + [UserRoleClaim.validators.includes("admin")]
+ override_global_claim_validators=lambda global_validators,
+ session,
+ user_context: global_validators + [UserRoleClaim.validators.includes("admin")]
)
def login(request: Request):
email = "..." # get from request body
# we use the email password recipe here, but you can use the recipe you use
- user = list_users_by_account_info("public", AccountInfo(email=email))
+ user = list_users_by_account_info("public", AccountInfoInput(email=email))
if len(user) == 0:
# return a 400 error to the client
return
- create_new_session(request, "public", user[0].login_methods[0].recipe_user_id, {"isImpersonation": True})
+ create_new_session(
+ request,
+ "public",
+ user[0].login_methods[0].recipe_user_id,
+ {"isImpersonation": True},
+ )
return jsonify({"message": "Impersonation complete!"})
+
```
```python
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
-from supertokens_python.recipe.session.asyncio import create_new_session
from django.http import HttpRequest, JsonResponse
-from supertokens_python.recipe.userroles import UserRoleClaim
+
from supertokens_python.asyncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo
+from supertokens_python.recipe.session.asyncio import create_new_session
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+from supertokens_python.recipe.userroles import UserRoleClaim
+from supertokens_python.types.base import AccountInfoInput
+
@verify_session(
# We add the UserRoleClaim's includes validator
- override_global_claim_validators=lambda global_validators, session, user_context: global_validators + \
- [UserRoleClaim.validators.includes("admin")]
+ override_global_claim_validators=lambda global_validators,
+ session,
+ user_context: global_validators + [UserRoleClaim.validators.includes("admin")]
)
async def impersonate(request: HttpRequest):
email = "..." # get from request body
# we use the email password recipe here, but you can use the recipe you use
- user = await list_users_by_account_info("public", AccountInfo(email=email))
+ user = await list_users_by_account_info("public", AccountInfoInput(email=email))
if len(user) == 0:
# return a 400 error to the client
return
- await create_new_session(request, "public", user[0].login_methods[0].recipe_user_id, {"isImpersonation": True})
+ await create_new_session(
+ request,
+ "public",
+ user[0].login_methods[0].recipe_user_id,
+ {"isImpersonation": True},
+ )
return JsonResponse({"message": "User logged in!"})
+
```
diff --git a/docs/post-authentication/user-management/account-deduplication.mdx b/docs/post-authentication/user-management/account-deduplication.mdx
index 433ef6e6f..7edd9676c 100644
--- a/docs/post-authentication/user-management/account-deduplication.mdx
+++ b/docs/post-authentication/user-management/account-deduplication.mdx
@@ -248,25 +248,34 @@ func main() {
```python
-from supertokens_python import init, InputAppInfo
-from supertokens_python.types import GeneralErrorResponse
+from typing import Any, Dict, Optional, Union
+
+from supertokens_python import InputAppInfo, init
+from supertokens_python.asyncio import list_users_by_account_info
from supertokens_python.recipe import passwordless, thirdparty
from supertokens_python.recipe.passwordless.interfaces import (
APIInterface as PasswordlessAPIInterface,
+)
+from supertokens_python.recipe.passwordless.interfaces import (
APIOptions as PasswordlessAPIOptions,
)
+from supertokens_python.recipe.session.interfaces import SessionContainer
from supertokens_python.recipe.thirdparty.interfaces import (
- RecipeInterface,
APIInterface as ThirdPartyAPIInterface,
+)
+from supertokens_python.recipe.thirdparty.interfaces import (
APIOptions as ThirdPartyAPIOptions,
)
-from typing import Union, Dict, Any, Optional
-from supertokens_python.recipe.session.interfaces import SessionContainer
-from supertokens_python.asyncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo
+from supertokens_python.recipe.thirdparty.interfaces import (
+ RecipeInterface,
+)
from supertokens_python.recipe.thirdparty.provider import Provider, RedirectUriInfo
-from supertokens_python.recipe.thirdparty.types import RawUserInfoFromProvider
-from supertokens_python.recipe.thirdparty.types import ThirdPartyInfo
+from supertokens_python.recipe.thirdparty.types import (
+ RawUserInfoFromProvider,
+ ThirdPartyInfo,
+)
+from supertokens_python.types import GeneralErrorResponse
+from supertokens_python.types.base import AccountInfoInput
def override_thirdparty_functions(original_implementation: RecipeInterface):
@@ -285,7 +294,7 @@ def override_thirdparty_functions(original_implementation: RecipeInterface):
user_context: Dict[str, Any],
):
existing_users = await list_users_by_account_info(
- tenant_id, AccountInfo(email=email)
+ tenant_id, AccountInfoInput(email=email)
)
if len(existing_users) == 0:
# this means this email is new so we allow sign up
@@ -384,7 +393,7 @@ def override_passwordless_apis(original_implementation: PasswordlessAPIInterface
):
if email is not None:
existing_users = await list_users_by_account_info(
- tenant_id, AccountInfo(email=email)
+ tenant_id, AccountInfoInput(email=email)
)
if len(existing_users) == 0:
# this means this email is new so we allow sign up
diff --git a/docs/post-authentication/user-management/allow-users-to-update-their-data.mdx b/docs/post-authentication/user-management/allow-users-to-update-their-data.mdx
index 12bb2e30c..de31b2924 100644
--- a/docs/post-authentication/user-management/allow-users-to-update-their-data.mdx
+++ b/docs/post-authentication/user-management/allow-users-to-update-their-data.mdx
@@ -94,9 +94,10 @@ func changeEmailAPI(w http.ResponseWriter, r *http.Request) {
```python
# the following example uses flask
-from supertokens_python.recipe.session.framework.flask import verify_session
from flask import Flask
+from supertokens_python.recipe.session.framework.flask import verify_session
+
app = Flask(__name__)
# highlight-start
@@ -253,16 +254,18 @@ func isValidEmail(email string) bool {
```python
-from supertokens_python.recipe.session.framework.flask import verify_session
-from supertokens_python.recipe.session import SessionContainer
-from supertokens_python.recipe.passwordless.syncio import update_user
+from re import fullmatch
+
+from flask import Flask, g, request
+
from supertokens_python.recipe.passwordless.interfaces import (
- UpdateUserOkResult,
- UpdateUserEmailAlreadyExistsError,
EmailChangeNotAllowedError,
+ UpdateUserEmailAlreadyExistsError,
+ UpdateUserOkResult,
)
-from flask import g, request, Flask
-from re import fullmatch
+from supertokens_python.recipe.passwordless.syncio import update_user
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.flask import verify_session
app = Flask(__name__)
@@ -381,9 +384,10 @@ func changeEmailAPI(w http.ResponseWriter, r *http.Request) {
```python
# the following example uses flask
-from supertokens_python.recipe.session.framework.flask import verify_session
from flask import Flask
+from supertokens_python.recipe.session.framework.flask import verify_session
+
app = Flask(__name__)
# highlight-start
@@ -603,24 +607,24 @@ func isValidEmail(email string) bool {
```python
-from supertokens_python.recipe.session.framework.flask import verify_session
-from supertokens_python.recipe.session import SessionContainer
-from supertokens_python.recipe.passwordless.syncio import update_user
-from supertokens_python.recipe.passwordless.interfaces import (
- UpdateUserOkResult,
- UpdateUserEmailAlreadyExistsError,
-)
+from re import fullmatch
+
+from flask import Flask, g, request
+from supertokens_python.recipe.accountlinking.syncio import is_email_change_allowed
from supertokens_python.recipe.emailverification.syncio import (
is_email_verified,
send_email_verification_email,
)
-
-from flask import g, request, Flask
-from re import fullmatch
-from supertokens_python.recipe.accountlinking.syncio import is_email_change_allowed
+from supertokens_python.recipe.passwordless.interfaces import (
+ UpdateUserEmailAlreadyExistsError,
+ UpdateUserOkResult,
+)
+from supertokens_python.recipe.passwordless.syncio import update_user
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.flask import verify_session
from supertokens_python.syncio import get_user, list_users_by_account_info
-from supertokens_python.types import AccountInfo
+from supertokens_python.types.base import AccountInfoInput
app = Flask(__name__)
@@ -662,7 +666,7 @@ def change_email():
if user is not None:
for tenant_id in user.tenant_ids:
users_with_same_email = list_users_by_account_info(
- tenant_id, AccountInfo(email=request_body["email"])
+ tenant_id, AccountInfoInput(email=request_body["email"])
)
for curr_user in users_with_same_email:
# Since one user can be shared across many tenants, we need to check if
@@ -847,28 +851,22 @@ func main() {
```python
-from supertokens_python import init, InputAppInfo, SupertokensConfig
-from supertokens_python.recipe import passwordless, emailverification
+from typing import Any, Dict, Optional
+
+from supertokens_python import (
+ InputAppInfo,
+ SupertokensConfig,
+ init,
+)
+from supertokens_python.recipe import emailverification, passwordless
from supertokens_python.recipe.emailverification.interfaces import (
APIInterface,
APIOptions,
-)
-
-from supertokens_python.recipe.passwordless.asyncio import update_user
-
-from supertokens_python.recipe.passwordless import ContactEmailOrPhoneConfig
-
-from supertokens_python.recipe.emailverification.interfaces import (
EmailVerifyPostOkResult,
)
-
+from supertokens_python.recipe.passwordless import ContactEmailOrPhoneConfig
+from supertokens_python.recipe.passwordless.asyncio import update_user
from supertokens_python.recipe.session.interfaces import SessionContainer
-from supertokens_python import (
- InputAppInfo,
- SupertokensConfig,
-)
-
-from typing import Optional, Dict, Any
def override_email_verification_apis(original_implementation: APIInterface):
@@ -988,9 +986,10 @@ func changePasswordAPI(w http.ResponseWriter, r *http.Request) {
```python
# the following example uses flask
-from supertokens_python.recipe.session.framework.flask import verify_session
from flask import Flask
+from supertokens_python.recipe.session.framework.flask import verify_session
+
app = Flask(__name__)
# highlight-start
@@ -1160,18 +1159,19 @@ func changePasswordAPI(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.framework.flask import verify_session
-from supertokens_python.recipe.session import SessionContainer
+from flask import g, request
+
+from supertokens_python.recipe.emailpassword.interfaces import (
+ PasswordPolicyViolationError,
+ WrongCredentialsError,
+)
from supertokens_python.recipe.emailpassword.syncio import (
- verify_credentials,
update_email_or_password,
+ verify_credentials,
)
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.flask import verify_session
from supertokens_python.syncio import get_user
-from supertokens_python.recipe.emailpassword.interfaces import (
- WrongCredentialsError,
- PasswordPolicyViolationError,
-)
-from flask import g, request
@app.route("/change-password", methods=["POST"]) # type: ignore
@@ -1348,18 +1348,21 @@ func changePasswordAPI(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.framework.flask import verify_session
-from supertokens_python.recipe.session.syncio import revoke_all_sessions_for_user
+from typing import cast
+
from flask import Flask
+
from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.flask import verify_session
+from supertokens_python.recipe.session.syncio import revoke_all_sessions_for_user
app = Flask(__name__)
@app.route('/change-password', methods=['POST']) # type: ignore
@verify_session()
def change_password():
-
- session: SessionContainer = g.supertokens # type: ignore
-
+
+ session: SessionContainer = cast(SessionContainer, g.supertokens) # type: ignore
+
# get the userId from the session object
user_id = session.get_user_id()
@@ -1368,7 +1371,7 @@ def change_password():
# highlight-start
# revoke all sessions for the user
revoke_all_sessions_for_user(user_id)
-
+
# revoke the user's current session, we do this to remove the auth cookies, logging out the user on the frontend
session.sync_revoke_session()
# highlight-end
diff --git a/docs/post-authentication/user-management/common-actions.mdx b/docs/post-authentication/user-management/common-actions.mdx
index faf53dbbb..7270b1cae 100644
--- a/docs/post-authentication/user-management/common-actions.mdx
+++ b/docs/post-authentication/user-management/common-actions.mdx
@@ -86,14 +86,15 @@ func main() {
```python
from supertokens_python.asyncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo
+from supertokens_python.types.base import AccountInfoInput
+
async def some_func():
# Note that users_info has type List[User]
- user_info = await list_users_by_account_info("public", AccountInfo(email="test@example.com"))
+ user_info = await list_users_by_account_info("public", AccountInfoInput(email="test@example.com"))
print(user_info)
- #
+ #
# user_info contains the following info:
# - emails
# - id
@@ -103,7 +104,7 @@ async def some_func():
# - third party login info
# - all the login methods associated with this user.
# - information about if the user's email is verified or not.
- #
+ #
```
@@ -112,14 +113,15 @@ async def some_func():
```python
from supertokens_python.syncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo
+from supertokens_python.types.base import AccountInfoInput
+
def some_func():
# Note that users_info has type List[User]
- user_info = list_users_by_account_info("public", AccountInfo(email="test@example.com"))
+ user_info = list_users_by_account_info("public", AccountInfoInput(email="test@example.com"))
print(user_info)
- #
+ #
# user_info contains the following info:
# - emails
# - id
@@ -129,7 +131,7 @@ def some_func():
# - third party login info
# - all the login methods associated with this user.
# - information about if the user's email is verified or not.
- #
+ #
```
@@ -206,11 +208,12 @@ func main() {
```python
from supertokens_python.asyncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo
+from supertokens_python.types.base import AccountInfoInput
+
async def some_func():
_ = await list_users_by_account_info(
- "public", AccountInfo(phone_number="+1234567890")
+ "public", AccountInfoInput(phone_number="+1234567890")
)
```
@@ -219,11 +222,12 @@ async def some_func():
```python
from supertokens_python.syncio import list_users_by_account_info
-from supertokens_python.types import AccountInfo
+from supertokens_python.types.base import AccountInfoInput
+
def some_func():
_ = list_users_by_account_info(
- "public", AccountInfo(phone_number="+1234567890")
+ "public", AccountInfoInput(phone_number="+1234567890")
)
```
@@ -756,10 +760,11 @@ func getUserInfoAPI(w http.ResponseWriter, r *http.Request) {
```python
-from supertokens_python.recipe.session.framework.fastapi import verify_session
+from fastapi import Depends, FastAPI
+
from supertokens_python.asyncio import get_user
from supertokens_python.recipe.session import SessionContainer
-from fastapi import FastAPI, Depends
+from supertokens_python.recipe.session.framework.fastapi import verify_session
app = FastAPI()
@@ -776,10 +781,11 @@ async def get_user_info_api(session: SessionContainer = Depends(verify_session()
```python
-from supertokens_python.recipe.session.framework.flask import verify_session
-from supertokens_python.syncio import get_user
from flask import Flask, g
+
from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.flask import verify_session
+from supertokens_python.syncio import get_user
app = Flask(__name__)
@@ -799,14 +805,18 @@ def get_user_info_api():
```python
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
-from supertokens_python.asyncio import get_user
+from typing import cast
+
from django.http import HttpRequest
+
+from supertokens_python.asyncio import get_user
from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+
@verify_session()
async def get_user_info_api(request: HttpRequest):
- session: SessionContainer = request.supertokens # type: ignore
+ session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore
user_id = session.get_user_id()
@@ -869,6 +879,7 @@ func main() {
```python
from supertokens_python.asyncio import delete_user
+
async def do_delete():
user_id = "..." # get the user ID somehow...
await delete_user(user_id) # this will succeed even if the userId didn't exist.
@@ -880,6 +891,7 @@ async def do_delete():
```python
from supertokens_python.syncio import delete_user
+
user_id = "..." # get the user ID somehow...
delete_user(user_id) # this will succeed even if the userId didn't exist.
```
@@ -982,6 +994,7 @@ func main() {
```python
from supertokens_python.asyncio import get_users_newest_first
+
async def some_func():
# get the latest 100 users
users_response = await get_users_newest_first("public")
@@ -992,7 +1005,7 @@ async def some_func():
# get for specific recipes
users_response = await get_users_newest_first(
"public",
- 200,
+ 200,
users_response.next_pagination_token,
# only get for those users who signed up with ^{recipeNameCapitalLetters}
["^{rid}"]
@@ -1003,9 +1016,9 @@ async def some_func():
```python
-
from supertokens_python.syncio import get_users_newest_first
+
# get the latest 100 users
users_response = get_users_newest_first("public")
@@ -1015,7 +1028,7 @@ users_response = get_users_newest_first("public", 200, users_response.next_pagin
# get for specific recipes
users_response = get_users_newest_first(
"public",
- 200,
+ 200,
users_response.next_pagination_token,
# only get for those users who signed up with ^{recipeNameCapitalLetters}
["^{rid}"]
@@ -1118,9 +1131,9 @@ func main() {
```python
-
from supertokens_python.asyncio import get_users_oldest_first
+
async def some_func():
# get the latest 100 users
users_response = await get_users_oldest_first("public")
@@ -1131,7 +1144,7 @@ async def some_func():
# get for specific recipes
users_response = await get_users_oldest_first(
"public",
- 200,
+ 200,
users_response.next_pagination_token,
# only get for those users who signed up with ^{recipeNameCapitalLetters}
["^{rid}"]
@@ -1142,9 +1155,9 @@ async def some_func():
```python
-
from supertokens_python.syncio import get_users_oldest_first
+
# get the latest 100 users
users_response = get_users_oldest_first("public")
@@ -1154,7 +1167,7 @@ users_response = get_users_oldest_first("public", 200, users_response.next_pagin
# get for specific recipes
users_response = get_users_oldest_first(
"public",
- 200,
+ 200,
users_response.next_pagination_token,
# only get for those users who signed up with ^{recipeNameCapitalLetters}
["^{rid}"]
@@ -1219,6 +1232,7 @@ func main() {
```python
from supertokens_python.asyncio import get_user_count
+
async def some_func():
user_count = await get_user_count()
@@ -1229,9 +1243,9 @@ async def some_func():
```python
-
from supertokens_python.syncio import get_user_count
+
user_count = get_user_count()
```
diff --git a/docs/quickstart/backend-setup.mdx b/docs/quickstart/backend-setup.mdx
index d79fb019d..1070e912c 100644
--- a/docs/quickstart/backend-setup.mdx
+++ b/docs/quickstart/backend-setup.mdx
@@ -505,9 +505,10 @@ Use the `Middleware` (**BEFORE all your routes**) and the `get_all_cors_headers(
```python
-from supertokens_python import get_all_cors_headers
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
+
+from supertokens_python import get_all_cors_headers
from supertokens_python.framework.fastapi import get_middleware
app = FastAPI()
@@ -583,10 +584,12 @@ Use the `Middleware` and the `get_all_cors_headers()` functions as shown below i
```python
-from supertokens_python import get_all_cors_headers
from typing import List
+
from corsheaders.defaults import default_headers
+from supertokens_python import get_all_cors_headers
+
CORS_ORIGIN_WHITELIST = [
"^{appInfo.websiteDomain}"
]
@@ -607,7 +610,7 @@ INSTALLED_APPS = [
'supertokens_python'
]
-MIDDLEWARE = [
+MIDDLEWARE = [ # type: ignore
'corsheaders.middleware.CorsMiddleware',
...,
# highlight-next-line
@@ -1009,10 +1012,12 @@ For your APIs that require a user to be logged in, use the `verify_session` midd
```python
-from supertokens_python.recipe.session.framework.fastapi import verify_session
-from supertokens_python.recipe.session import SessionContainer
from fastapi import Depends
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.fastapi import verify_session
+
+
# highlight-start
@app.post('/like_comment') # type: ignore
async def like_comment(session: SessionContainer = Depends(verify_session())):
@@ -1026,10 +1031,12 @@ async def like_comment(session: SessionContainer = Depends(verify_session())):
```python
-from supertokens_python.recipe.session.framework.flask import verify_session
-from supertokens_python.recipe.session import SessionContainer
from flask import g
+from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.flask import verify_session
+
+
# highlight-start
@app.route('/update-jwt', methods=['POST']) # type: ignore
@verify_session()
@@ -1046,14 +1053,18 @@ def like_comment():
```python
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+from typing import cast
+
from django.http import HttpRequest
+
from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+
# highlight-start
@verify_session()
async def like_comment(request: HttpRequest):
- session: SessionContainer = request.supertokens # type: ignore
+ session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore
user_id = session.get_user_id()
# highlight-end
diff --git a/docs/references/backend-sdks/function-overrides.mdx b/docs/references/backend-sdks/function-overrides.mdx
index 905fe444c..137f954b5 100644
--- a/docs/references/backend-sdks/function-overrides.mdx
+++ b/docs/references/backend-sdks/function-overrides.mdx
@@ -179,15 +179,19 @@ See all the [functions that can be overridden here](https://supertokens.com/docs
:::
```python
-from supertokens_python import init, InputAppInfo
-from supertokens_python.recipe import thirdparty
-from supertokens_python.recipe import session
-from supertokens_python.recipe.thirdparty.interfaces import RecipeInterface as ThirdPartyRecipeInterface
-from supertokens_python.recipe.session.interfaces import RecipeInterface as SessionRecipeInterface
+from typing import Any, Dict, Optional, Union
+
+from supertokens_python import InputAppInfo, init
+from supertokens_python.recipe import session, thirdparty
+from supertokens_python.recipe.session.interfaces import (
+ RecipeInterface as SessionRecipeInterface,
+)
+from supertokens_python.recipe.session.interfaces import SessionContainer
+from supertokens_python.recipe.thirdparty.interfaces import (
+ RecipeInterface as ThirdPartyRecipeInterface,
+)
from supertokens_python.recipe.thirdparty.types import RawUserInfoFromProvider
from supertokens_python.types import RecipeUserId
-from typing import Dict, Any, Optional, Union
-from supertokens_python.recipe.session.interfaces import SessionContainer
# highlight-start
@@ -374,10 +378,11 @@ func main() {
```python
-from supertokens_python.recipe.session.asyncio import get_all_session_handles_for_user
+from typing import Any, Dict, Optional
+
from supertokens_python.recipe import session
+from supertokens_python.recipe.session.asyncio import get_all_session_handles_for_user
from supertokens_python.recipe.session.interfaces import RecipeInterface
-from typing import Any, Dict, Optional
from supertokens_python.types import RecipeUserId
@@ -715,7 +720,7 @@ app = FastAPI()
async def exception_handler(_, exc: Exception):
if str(exc) == "Session already exists on another device":
pass # TODO: send custom response
-
+
# TODO: Send generic 500 response
```
@@ -731,7 +736,7 @@ app = Flask(__name__)
def all_exception_handler(exc: Exception):
if str(exc) == "Session already exists on another device":
pass # TODO: send custom response
-
+
# TODO: Send generic 500 response
```
@@ -741,21 +746,24 @@ def all_exception_handler(exc: Exception):
```python
# Add this middlware in settings.py
+from typing import cast
+
from django.http import HttpRequest, HttpResponse
+
class ErrorHandlerMiddleware:
def __init__(self, get_response): # type: ignore
self.get_response = get_response
def __call__(self, request: HttpRequest):
- response: HttpResponse = self.get_response(request)
+ response: HttpResponse = cast(HttpResponse, self.get_response(request))
return response
def process_exception(self, request: HttpRequest, exception: Exception) -> HttpResponse:
if exception and str(exception) == "Session already exists on another device":
pass # TODO: send custom response
-
+
return HttpResponse("Error processing the request.", status=500)
```
@@ -867,10 +875,12 @@ func main() {
We use the `get_request_from_user_context` function provided by the SDK to get the request object from the user context.
```python
+from typing import Any, Dict
+
from supertokens_python import get_request_from_user_context
from supertokens_python.recipe import session
-from supertokens_python.recipe.session.interfaces import RecipeInterface
-from typing import Any, Dict
+from supertokens_python.recipe.session.interfaces import RecipeInterface
+
def override_session_functions(original_implementation: RecipeInterface):
original_revoke_session = original_implementation.revoke_session
@@ -885,12 +895,12 @@ def override_session_functions(original_implementation: RecipeInterface):
else:
#
# This is possible if the function is triggered from the user management dashboard
- #
+ #
# In this case set a reasonable default value to use
#
customHeaderValue="default"
# highlight-end
-
+
print(customHeaderValue)
# Perform custom logic based on the value of customHeadervalue
From 2ce401c92828b2bb4c6b02881b8562f77e48541e Mon Sep 17 00:00:00 2001
From: Namit Nathwani
Date: Fri, 27 Jun 2025 19:54:09 +0530
Subject: [PATCH 10/10] fix: pyright errors
---
docs/authentication/m2m/legacy-flow.mdx | 2 +-
docs/authentication/passwordless/allow-list-flow.mdx | 4 ++--
.../session-management/session-invalidation.mdx | 8 ++++++--
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/docs/authentication/m2m/legacy-flow.mdx b/docs/authentication/m2m/legacy-flow.mdx
index 59ccb7b21..1e149f2aa 100644
--- a/docs/authentication/m2m/legacy-flow.mdx
+++ b/docs/authentication/m2m/legacy-flow.mdx
@@ -596,7 +596,7 @@ app.post("/like-comment", async (req, res, next) => {
```python
-from typing import Optional, Union, cast
+from typing import Optional, cast
from django.http import HttpRequest
diff --git a/docs/authentication/passwordless/allow-list-flow.mdx b/docs/authentication/passwordless/allow-list-flow.mdx
index 7cdd137d2..18692342b 100644
--- a/docs/authentication/passwordless/allow-list-flow.mdx
+++ b/docs/authentication/passwordless/allow-list-flow.mdx
@@ -353,7 +353,7 @@ from supertokens_python.recipe.passwordless.interfaces import (
APIOptions,
)
from supertokens_python.recipe.session.interfaces import SessionContainer
-from supertokens_python.types import AccountInfo, GeneralErrorResponse
+from supertokens_python.types import GeneralErrorResponse
from supertokens_python.types.base import AccountInfoInput
@@ -405,7 +405,7 @@ def override_passwordless_apis(original_implementation: APIInterface):
else:
assert phone_number is not None
existing_user = await list_users_by_account_info(
- tenant_id, AccountInfo(phone_number=phone_number)
+ tenant_id, AccountInfoInput(phone_number=phone_number)
)
user_with_passwordless = next(
(
diff --git a/docs/post-authentication/session-management/session-invalidation.mdx b/docs/post-authentication/session-management/session-invalidation.mdx
index c5b3ea34d..f82d4cad6 100644
--- a/docs/post-authentication/session-management/session-invalidation.mdx
+++ b/docs/post-authentication/session-management/session-invalidation.mdx
@@ -508,14 +508,18 @@ def some_api():
```python
-from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+from typing import cast
+
from django.http import HttpRequest
+
from supertokens_python.recipe.session import SessionContainer
+from supertokens_python.recipe.session.framework.django.asyncio import verify_session
+
# highlight-start
@verify_session()
async def some_api(request: HttpRequest):
- session: SessionContainer = request.supertokens # type: ignore This will delete the session from the db and from the frontend (cookies)
+ session: SessionContainer = cast(SessionContainer, request.supertokens) # type: ignore This will delete the session from the db and from the frontend (cookies)
# highlight-end
await session.revoke_session()
```