supertokens / supertokens-python Goto Github PK
View Code? Open in Web Editor NEWPython SDK for SuperTokens
Home Page: https://supertokens.com
License: Other
Python SDK for SuperTokens
Home Page: https://supertokens.com
License: Other
supertokens_python.querier
, supertokens_python.normalised_url_path
etc..Please refer to node PR linked to this issue: supertokens/supertokens-golang#36
Inside example/fastapi, have a folder for each type of app:
Likewise for other frameworks.
NodeJS PR: supertokens/supertokens-node#210
RIght now, each of them has a class return type, but return a child of the that class. The problem with the way we return things now is that The super class takes all possible input params, so for example, even if the status is 'OK', the user
param in the return is Union[User, None]
.
This causes a problem in consuming them since if we check response.is_ok
then the type of response.user
is still Union[User, None]
. This forces us to do things like:
if response.user is None:
raise Exception("Should never come here")
# consume response.user
Instead, what we should do is that return a union of sub child instead of the super class. And each of the sub child should take the appropriate params as non optional and non None
. Then during consuming them, we can use isinstance()
to know the result type.
Refer to the node JS pr here (the second nodejs PR, for which you will have to scroll down in the issue)
I am getting this error after executing the sample code below:
/Users/luke/PycharmProjects/supertoken/venv1/lib/python3.10/site-packages/supertokens_python/recipe/session/recipe_implementation.py:81: RuntimeWarning: coroutine 'RecipeImplementation.__init__.<locals>.call_get_handshake_info' was never awaited
pass
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
INFO: Started server process [9584]
INFO: Waiting for application startup.
INFO: Application startup complete.
--- Logging error ---
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/logging/__init__.py", line 1100, in emit
msg = self.format(record)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/logging/__init__.py", line 943, in format
return fmt.format(record)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/logging/__init__.py", line 678, in format
record.message = record.getMessage()
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/logging/__init__.py", line 368, in getMessage
msg = msg % self.args
TypeError: %d format: a real number is required, not str
Call stack:
File "/Users/luke/PycharmProjects/supertoken/main.py", line 109, in <module>
uvicorn.run(app, host="0.0.0.0", port=get_api_port()) # type: ignore
File "/Users/luke/PycharmProjects/supertoken/venv1/lib/python3.10/site-packages/uvicorn/main.py", line 452, in run
server.run()
File "/Users/luke/PycharmProjects/supertoken/venv1/lib/python3.10/site-packages/uvicorn/server.py", line 68, in run
return asyncio.run(self.serve(sockets=sockets))
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/asyncio/base_events.py", line 633, in run_until_complete
self.run_forever()
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/asyncio/base_events.py", line 600, in run_forever
self._run_once()
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/asyncio/base_events.py", line 1896, in _run_once
handle._run()
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/asyncio/events.py", line 80, in _run
self._context.run(self._callback, *self._args)
File "/Users/luke/PycharmProjects/supertoken/venv1/lib/python3.10/site-packages/uvicorn/server.py", line 86, in serve
await self.startup(sockets=sockets)
File "/Users/luke/PycharmProjects/supertoken/venv1/lib/python3.10/site-packages/uvicorn/server.py", line 176, in startup
self._log_started_message(listeners)
File "/Users/luke/PycharmProjects/supertoken/venv1/lib/python3.10/site-packages/uvicorn/server.py", line 217, in _log_started_message
logger.info(
Message: 'Uvicorn running on %s://%s:%d (Press CTRL+C to quit)'
Arguments: ('http', '0.0.0.0', '3001')
import os
import typing
from typing import Union
import uvicorn # type: ignore
from dotenv import load_dotenv
from fastapi import Depends, FastAPI, Response
from fastapi.responses import JSONResponse, PlainTextResponse
from starlette.datastructures import Headers
from starlette.exceptions import ExceptionMiddleware
from starlette.middleware.cors import CORSMiddleware
from starlette.types import ASGIApp
from supertokens_python import (InputAppInfo, SupertokensConfig,
get_all_cors_headers, init)
from supertokens_python.framework.fastapi import Middleware
from supertokens_python.recipe import session, thirdpartyemailpassword
from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.session.framework.fastapi import verify_session
from supertokens_python.recipe.thirdpartyemailpassword import (
Apple, Discord, Github, Google, GoogleWorkspaces)
load_dotenv()
app = FastAPI(debug=True)
app.add_middleware(Middleware)
os.environ.setdefault('SUPERTOKENS_ENV', 'testing')
def get_api_port():
return '3001'
def get_website_port():
return '3000'
def get_website_domain():
return 'http://localhost:' + get_website_port()
init(
supertokens_config=SupertokensConfig(
connection_uri='https://try.supertokens.io'
),
app_info=InputAppInfo(
app_name='Supertokens',
api_domain='0.0.0.0' + get_api_port(),
website_domain=get_website_domain()
),
framework='fastapi',
recipe_list=[
session.init(),
],
telemetry=False
)
app.add_middleware(ExceptionMiddleware, handlers=app.exception_handlers)
@app.get('/sessioninfo')
async def get_session_info(session_: SessionContainer = Depends(verify_session())):
return JSONResponse({
'sessionHandle': session_.get_handle(),
'userId': session_.get_user_id(),
'accessTokenPayload': session_.get_access_token_payload(),
# 'sessionData': await session_.get_session_data()
})
@app.exception_handler(405) # type: ignore
def f_405(_, __: Exception):
return PlainTextResponse('', status_code=404)
class CustomCORSMiddleware(CORSMiddleware):
def __init__(
self,
app_: ASGIApp,
allow_origins: typing.Sequence[str] = (),
allow_methods: typing.Sequence[str] = ("GET",),
allow_headers: typing.Sequence[str] = (),
allow_credentials: bool = False,
allow_origin_regex: Union[str, None] = None,
expose_headers: typing.Sequence[str] = (),
max_age: int = 600,
) -> None:
super().__init__(app_, allow_origins, allow_methods, allow_headers, allow_credentials, allow_origin_regex, expose_headers, max_age) # type: ignore
def preflight_response(self, request_headers: Headers) -> Response:
result: Response = super().preflight_response(request_headers)
if result.status_code == 200: # type: ignore
result.headers.__delitem__('content-type')
result.headers.__delitem__('content-length')
return Response(status_code=204, headers=dict(result.headers))
return result
app = CustomCORSMiddleware( # type: ignore
app_=app,
allow_origins=[
get_website_domain()
],
allow_credentials=True,
allow_methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"],
allow_headers=["Content-Type"] + get_all_cors_headers(),
)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=get_api_port()) # type: ignore```
In local dev on every fastapi app, you have a built-in docs page that lists all api routes and lets you manually exercise them for testing.
Supertokens integration into a fastapi app shouldn't break this docs page.
I'm still verifying at the moment whether it was supertokens or my own code that broke the docs page
Make tests like https://github.com/supertokens/supertokens-node/blob/8.1/test/recipeModuleManager.test.js#L629 and https://github.com/supertokens/supertokens-node/blob/8.1/test/recipeModuleManager.test.js#L665
These are two form of override scenarios which need to be accounted for. The second test would imply that your tpep implementations (for recipe and api interface), would need to change slightly.
Related to supertokens/supertokens-node#199
Hey folks,
We just noticed all of our test pipelines were broken because the supertokens-flask python package and the supertokens-flask repo were suddenly deleted. Would it be possible to just keep the repo in archived mode ?
This move looks quite brutal to me, and right now we're left with no easy path to unbreak our CI and all of our projects. If the repo was still up we could have forked it and maintained a fork on our side until we're ready to migrate to a newer version, but we don't even have that option.
FYI, we're using ST 2.5.x, using flask, with no frontend SDK.
Therefore, I have to merge 0.1 version with jwt_recipe and continue to update the python code(get_session function for example)
As the allowed values are {'Strict', 'Lax', 'None'}
It seems to be impossible to set cookie_same_site
value in config of the session recipe due to same_site.lower()
called on normalise_same_site
:
def normalise_same_site(same_site: str) -> str:
same_site = same_site.strip()
same_site = same_site.lower() # This line should be removed to fix it.
allowed_values = {'Strict', 'Lax', 'None'}
if same_site not in allowed_values:
raise Exception(
'cookie same site must be one of "Strict", "Lax", or "None"')
return same_site
I just try to create a PR to fix it but it seems I'm not allowed to do that.
Can you fix it please ?
Right now, The same user type class is used across recipes when the super recipe is using a sub recipe. This results in inconsistency in the type of the user object that is provided to the developer.
We should stick to the same user object type per recipe
Fix "<Task pending name='Task-182' coro=<<async_generator_athrow without name>()>>" error -> run frontendIntegration/flask test. This is caused by running the handshake info in the background initially. If we do not run it in the background, this error doesn't come.
Add all tests from node SDK for this
For all non-GET API calls.
The payload may contain a utf-8 string and make sure that when you decode the base64 string and deserialize the JSON, you take this into consideraion.
I have a fastapi project using supertokens-python with the following init configuration:
init(
app_info=InputAppInfo(
app_name=APP_NAME,
api_domain=API_DOMAIN,
website_domain=WEBSITE_DOMAIN,
api_base_path=API_BASE_PATH,
website_base_path=WEBSITE_BASE_PATH,
),
supertokens_config=SupertokensConfig(
connection_uri=SUPERTOKENS_CONNECTION_URL
),
framework="fastapi",
recipe_list=[
session.init(
jwt=session.JWTConfig(enable=True),
),
passwordless.init(
flow_type="MAGIC_LINK",
contact_config=ContactEmailOnlyConfig(
create_and_send_custom_email=login_flow
),
),
thirdparty.init(
override=thirdparty.InputOverrideConfig(apis=override_thirdparty_apis),
sign_in_and_up_feature=thirdparty.SignInAndUpFeature(
providers=[
Google(
client_id=GOOGLE_CLIENT_ID,
client_secret=GOOGLE_CLIENT_SECRET,
),
Github(
client_id=GITHUB_CLIENT_ID,
client_secret=GITHUB_CLIENT_SECRET,
),
Apple(
client_id=APPLE_CLIENT_ID,
client_key_id=APPLE_CLIENT_KEY_ID,
client_private_key=APPLE_CLIENT_PRIVATE_KEY,
client_team_id=APPLE_CLIENT_TEAM_ID,
),
Facebook(
client_id=FACEBOOK_CLIENT_ID,
client_secret=FACEBOOK_CLIENT_SECRET,
),
]
),
),
],
mode="asgi", # use wsgi if you are running using gunicorn
telemetry=False,
)
I have some integration tests for the passwordless login flow that are working normally with that configuration.
I would like to add custom data to the user's session access token, so I tried following the docs: https://supertokens.com/docs/passwordless/common-customizations/user-roles/assigning-session-roles
And updated the configuration with my override_functions implementation:
session.init(
override=session.InputOverrideConfig(functions=override_functions),
jwt=session.JWTConfig(enable=True),
),
Now the integration test for the passwordless flow fails when trying to consume the created code (POSTing to /api/signinup/code/consume
) with a 500. I even tried using an empty override implementation as it follows but it still returns the 500:
from supertokens_python import init, InputAppInfo
from supertokens_python.recipe.session.interfaces import RecipeInterface
from supertokens_python.recipe import session
from typing import Union, Dict, Any
def override_functions(original_implementation: RecipeInterface):
original_implementation_create_new_session = original_implementation.create_new_session
async def create_new_session(request: Any, user_id: str,
access_token_payload: Union[None, Dict[str, Any]],
session_data: Union[None, Dict[str, Any]], user_context: Dict[str, Any]):
return await original_implementation_create_new_session(request, user_id, access_token_payload, session_data, user_context)
original_implementation.create_new_session = create_new_session
return original_implementation
Right now, somewhere it's request.original
, other places it's request.req
etc.. We need to make all of them accessible via request.original
.
This should be done in a non breaking way.
-get_users_oldest_first
get_users_newest_first
delete_user
get_user_count
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.