Skip to content

Commit b1fb9b1

Browse files
Merge pull request #209 from supertokens/feat/session-grants
feat: Add session claims feature
2 parents 0d8f991 + df5994f commit b1fb9b1

File tree

136 files changed

+5574
-2630
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

136 files changed

+5574
-2630
lines changed

.github/workflows/tests.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,10 @@ jobs:
5151
run: cd ../supertokens-root && ./loadModules
5252
- name: Setting up supertokens-root test environment
5353
run: cd ../supertokens-root && bash ./utils/setupTestEnvLocal
54+
- name: Debugging with tmate
55+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
56+
uses: mxschmitt/[email protected]
57+
with:
58+
sudo: false
5459
- name: Run tests
55-
run: make test
60+
run: make test

CHANGELOG.md

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,165 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [unreleased]
88

9+
### Changes
10+
11+
- Made the `email` parameter option in `unverify_email`, `revoke_email_verification_tokens`, `is_email_verified`, `verify_email_using_token`, `create_email_verification_token` of the `EmailVerification` recipe.
12+
13+
### Added
14+
15+
- Added support for session claims with related interfaces and classes.
16+
- Added `on_invalid_claim` optional error handler to send InvalidClaim error responses.
17+
- Added `INVALID_CLAIMS` (`InvalidClaimError`) to `SessionErrors`.
18+
- Added `invalid_claim_status_code` optional config to set the status code of InvalidClaim errors.
19+
- Added `override_global_claim_validators` as param of `get_session` and `verify_session`.
20+
- Added `merge_into_access_token_payload` to the Session recipe and session objects which should be preferred to the now deprecated `update_access_token_payload`.
21+
- Added `EmailVerificationClaim`, `UserRoleClaim` and `PermissionClaim`. These claims are now added to the access token payload by default by their respective recipes.
22+
- Added `assert_claims`, `validate_claims_for_session_handle`, `validate_claims_in_jwt_payload` to the Session recipe to support validation of the newly added claims.
23+
- Added `fetch_and_set_claim`, `get_claim_value`, `set_claim_value` and `remove_claim` to the Session recipe to manage claims.
24+
- Added `assert_claims`, `fetch_and_set_claim`, `get_claim_value`, `set_claim_value` and `remove_claim` to session objects to manage claims.
25+
- Added session to the input of `generate_email_verify_token_post`, `verify_email_post`, `is_email_verified_get`.
26+
- Adds default userContext for verifySession calls that contains the request object.
27+
28+
### Breaking Changes
29+
- Changed `sign_in_up` third party recipe function to accept just the email as `str` (removed `email_verified: bool`).
30+
- The frontend SDK should be updated to a version supporting session claims!
31+
- supertokens-auth-react: >= 0.25.0
32+
- supertokens-web-js: >= 0.2.0
33+
- `EmailVerification` recipe is now not initialized as part of auth recipes, it should be added to the `recipe_list` directly instead using `emailverification.init()`.
34+
- Email verification related overrides (`email_verification_feature` attr of `override`) moved from auth recipes into the `EmailVerification` recipe config.
35+
- Email verification related configs (`email_verification_feature` attr) moved from auth recipes into the `EmailVerification` config object root.
36+
- ThirdParty recipe no longer takes `email_delivery` config. use `emailverification` recipe's `email_delivery` instead.
37+
- Moved email verification related configs from the `email_delivery` config of auth recipes into a separate `EmailVerification` email delivery config.
38+
- Updated return type of `get_email_for_user_id` in the `EmailVerification` recipe config. It should now return an object with status.
39+
- Removed `get_reset_password_url`, `get_email_verification_url`, `get_link_domain_and_path`. Changing these urls can be done in the email delivery configs instead.
40+
- Removed `unverify_email`, `revoke_email_verification_tokens`, `is_email_verified`, `verify_email_using_token` and `create_email_verification_token` from auth recipes. These should be called on the `EmailVerification` recipe instead.
41+
- Changed function signature for email verification APIs to accept a session as an input.
42+
- Changed Session API interface functions:
43+
- `refresh_post` now returns a Session container object.
44+
- `sign_out_post` now takes in an optional session object as a parameter.
45+
46+
### Migration
47+
Before:
48+
```python
49+
from supertokens_python import init, SupertokensConfig, InputAppInfo
50+
from supertokens_python.recipe import emailpassword
51+
from supertokens_python.recipe.emailverification.utils import OverrideConfig
52+
53+
init(
54+
supertokens_config=SupertokensConfig("..."),
55+
app_info=InputAppInfo("..."),
56+
framework="...",
57+
recipe_list=[
58+
emailpassword.init(
59+
# these options should be moved into the EmailVerification config:
60+
email_verification_feature=emailpassword.InputEmailVerificationConfig("..."),
61+
override=emailpassword.InputOverrideConfig(
62+
email_verification_feature=OverrideConfig(
63+
# these overrides should be moved into the EmailVerification overrides
64+
"..."
65+
)
66+
),
67+
),
68+
],
69+
)
70+
```
71+
72+
After the update:
73+
74+
```python
75+
from supertokens_python import init, SupertokensConfig, InputAppInfo
76+
from supertokens_python.recipe import emailpassword, emailverification
77+
78+
init(
79+
supertokens_config=SupertokensConfig("..."),
80+
app_info=InputAppInfo("..."),
81+
framework="...",
82+
recipe_list=[
83+
emailverification.init(
84+
"...", # EmailVerification config
85+
override=emailverification.OverrideConfig(
86+
# overrides
87+
"..."
88+
),
89+
),
90+
emailpassword.init(),
91+
],
92+
)
93+
```
94+
95+
#### Passwordless users and email verification
96+
97+
If you turn on email verification your email-based passwordless users may be redirected to an email verification screen in their existing session.
98+
Logging out and logging in again will solve this problem or they could click the link in the email to verify themselves.
99+
100+
You can avoid this by running a script that will:
101+
102+
1. list all users of passwordless
103+
2. create an emailverification token for each of them if they have email addresses
104+
3. user the token to verify their address
105+
106+
Something similar to this script:
107+
108+
```python
109+
from supertokens_python import init, SupertokensConfig, InputAppInfo
110+
from supertokens_python.recipe import passwordless, emailverification, session
111+
from supertokens_python.recipe.passwordless import ContactEmailOrPhoneConfig
112+
113+
114+
from supertokens_python.syncio import get_users_newest_first
115+
from supertokens_python.recipe.emailverification.syncio import create_email_verification_token, verify_email_using_token
116+
from supertokens_python.recipe.emailverification.interfaces import CreateEmailVerificationTokenOkResult
117+
118+
init(
119+
supertokens_config=SupertokensConfig("http://localhost:3567"),
120+
app_info=InputAppInfo(
121+
app_name="SuperTokens Demo",
122+
api_domain="https://api.supertokens.io",
123+
website_domain="supertokens.io",
124+
),
125+
framework="fastapi",
126+
recipe_list=[
127+
emailverification.init("REQUIRED"),
128+
passwordless.init(
129+
contact_config=ContactEmailOrPhoneConfig(),
130+
flow_type="USER_INPUT_CODE_AND_MAGIC_LINK",
131+
),
132+
session.init(),
133+
],
134+
)
135+
136+
def verify_email_for_passwordless_users():
137+
pagination_token = None
138+
done = False
139+
140+
while not done:
141+
res = get_users_newest_first(
142+
limit=100,
143+
pagination_token=pagination_token,
144+
include_recipe_ids=["passwordless"]
145+
)
146+
147+
for user in res.users:
148+
if user.email is not None:
149+
token_res = create_email_verification_token(user.user_id, user.email)
150+
if isinstance(token_res, CreateEmailVerificationTokenOkResult):
151+
verify_email_using_token(token_res.token)
152+
153+
done = res.next_pagination_token is None
154+
if not done:
155+
pagination_token = res.next_pagination_token
156+
157+
verify_email_for_passwordless_users()
158+
```
159+
160+
#### User roles
161+
162+
The `UserRoles` recipe now adds role and permission information into the access token payload by default. If you are already doing this manually, this will result in duplicate data in the access token.
163+
164+
- You can disable this behaviour by setting `skip_adding_roles_to_access_token` and `skip_adding_permissions_to_access_token` to true in the recipe init.
165+
- Check how to use the new claims in the updated guide: https://supertokens.com/docs/userroles/protecting-routes
166+
167+
9168
## [0.10.4] - 2022-08-30
10169
## Features:
11170
- Add support for User ID Mapping using `create_user_id_mapping`, `get_user_id_mapping`, `delete_user_id_mapping`, `update_or_delete_user_id_mapping` functions

dev-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,4 @@ uvicorn==0.18.2
8282
Werkzeug==2.0.3
8383
wrapt==1.13.3
8484
zipp==3.7.0
85+
pytest-mock==3.8.2

examples/with-django/with-thirdpartyemailpassword/project/settings.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@
2222
get_all_cors_headers,
2323
init,
2424
)
25-
from supertokens_python.recipe import session, thirdpartyemailpassword
25+
from supertokens_python.recipe import (
26+
session,
27+
thirdpartyemailpassword,
28+
emailverification,
29+
)
2630
from supertokens_python.recipe.thirdpartyemailpassword import (
2731
Apple,
2832
Discord,
@@ -62,6 +66,7 @@ def get_website_domain():
6266
mode="wsgi",
6367
recipe_list=[
6468
session.init(),
69+
emailverification.init("REQUIRED"),
6570
thirdpartyemailpassword.init(
6671
providers=[
6772
Google(

examples/with-fastapi/with-thirdpartyemailpassword/main.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
init,
1414
)
1515
from supertokens_python.framework.fastapi import get_middleware
16-
from supertokens_python.recipe import session, thirdpartyemailpassword
16+
from supertokens_python.recipe import (
17+
session,
18+
thirdpartyemailpassword,
19+
emailverification,
20+
)
1721
from supertokens_python.recipe.session import SessionContainer
1822
from supertokens_python.recipe.session.framework.fastapi import verify_session
1923
from supertokens_python.recipe.thirdpartyemailpassword import (
@@ -52,6 +56,7 @@ def get_website_domain():
5256
framework="fastapi",
5357
recipe_list=[
5458
session.init(),
59+
emailverification.init("REQUIRED"),
5560
thirdpartyemailpassword.init(
5661
providers=[
5762
Google(

examples/with-flask/with-thirdpartyemailpassword/app.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@
1010
init,
1111
)
1212
from supertokens_python.framework.flask import Middleware
13-
from supertokens_python.recipe import session, thirdpartyemailpassword
13+
from supertokens_python.recipe import (
14+
session,
15+
thirdpartyemailpassword,
16+
emailverification,
17+
)
1418
from supertokens_python.recipe.session.framework.flask import verify_session
1519
from supertokens_python.recipe.thirdpartyemailpassword import (
1620
Apple,
@@ -45,6 +49,7 @@ def get_website_domain():
4549
framework="flask",
4650
recipe_list=[
4751
session.init(),
52+
emailverification.init("REQUIRED"),
4853
thirdpartyemailpassword.init(
4954
providers=[
5055
Google(

frontendDriverInterfaceSupported.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"_comment": "contains a list of frontend-driver interfaces branch names that this core supports",
33
"versions": [
4-
"1.14"
4+
"1.14", "1.15"
55
]
66
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.
2+
#
3+
# This software is licensed under the Apache License, Version 2.0 (the
4+
# "License") as published by the Apache Software Foundation.
5+
#
6+
# You may not use this file except in compliance with the License. You may
7+
# obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
from typing import Callable, List
16+
17+
18+
class PostSTInitCallbacks:
19+
"""Callbacks that are called after the SuperTokens instance is initialized."""
20+
21+
callbacks: List[Callable[[], None]] = []
22+
23+
@staticmethod
24+
def add_post_init_callback(cb: Callable[[], None]) -> None:
25+
PostSTInitCallbacks.callbacks.append(cb)
26+
27+
@staticmethod
28+
def run_post_init_callbacks() -> None:
29+
for cb in PostSTInitCallbacks.callbacks:
30+
cb()
31+
32+
PostSTInitCallbacks.callbacks = []

supertokens_python/recipe/emailpassword/__init__.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
exceptions = ex
2727
InputOverrideConfig = utils.InputOverrideConfig
2828
InputResetPasswordUsingTokenFeature = utils.InputResetPasswordUsingTokenFeature
29-
InputEmailVerificationConfig = utils.InputEmailVerificationConfig
3029
InputSignUpFeature = utils.InputSignUpFeature
3130
InputFormField = utils.InputFormField
3231
SMTPService = emaildelivery_services.SMTPService
@@ -42,14 +41,12 @@ def init(
4241
reset_password_using_token_feature: Union[
4342
utils.InputResetPasswordUsingTokenFeature, None
4443
] = None,
45-
email_verification_feature: Union[utils.InputEmailVerificationConfig, None] = None,
4644
override: Union[utils.InputOverrideConfig, None] = None,
4745
email_delivery: Union[EmailDeliveryConfig[EmailTemplateVars], None] = None,
4846
) -> Callable[[AppInfo], RecipeModule]:
4947
return EmailPasswordRecipe.init(
5048
sign_up_feature,
5149
reset_password_using_token_feature,
52-
email_verification_feature,
5350
override,
5451
email_delivery,
5552
)

supertokens_python/recipe/emailpassword/api/implementation.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,9 @@ async def generate_password_reset_token_post(
9292

9393
token = token_result.token
9494
password_reset_link = (
95-
await api_options.config.reset_password_using_token_feature.get_reset_password_url(
96-
user, user_context
97-
)
98-
+ "?token="
95+
api_options.app_info.website_domain.get_as_string_dangerous()
96+
+ api_options.app_info.website_base_path.get_as_string_dangerous()
97+
+ "/reset-password?token="
9998
+ token
10099
+ "&rid="
101100
+ api_options.recipe_id

0 commit comments

Comments
 (0)