Git Product home page Git Product logo

supertokens-python's Introduction

SuperTokens banner

SuperTokens Python SDK

chat on Discord Last 30 days downloads for supertokens-python

About

This is a Python library that is used to interface between a python API process and the SuperTokens http service.

Learn more at https://supertokens.com

Documentation

To see documentation, please click here.

Contributing

Please see the CONTRIBUTING.md file for instructions.

Contact us

For any queries, or support requests, please email us at [email protected], or join our Discord server.

Authors

Created with ❤️ by the folks at SuperTokens.io.

supertokens-python's People

Contributors

anku255 avatar bhumilsarvaiya avatar frost-nzcr4 avatar girish946 avatar iammayankthakur avatar iresharma avatar jinpan avatar jscyo avatar kshivendu avatar nkshah2 avatar porcellus avatar rishabhpoddar avatar rossoskull avatar sattvikc avatar st-jay avatar xuatz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

supertokens-python's Issues

Add more tests

-get_users_oldest_first

  • get_users_newest_first
  • delete_user
  • get_user_count
  • Django2x frontend integration test with supertokens-website

Can we get supertokens-flask back ?

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.

Supertokens integration shouldn't break built-in docs page [fastapi]

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

Unable to set cookie_same_site in config of session recipe

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 ?

Fix background task issue

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.

RuntimeWarning: coroutine was never awaited

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```

Change how API and Recipe interface functions return their result

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.

Fix example folder structure

Inside example/fastapi, have a folder for each type of app:

  • with-thirdparty
  • with-thirdpartyemailpassword

Likewise for other frameworks.

Overriding createNewSession is not working + framework dependency issue

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

Fix user type across recipes

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

Docs changes for release

  • Merge master into your branch
  • In introduction, we should not add flask and django as being released. They should still be in coming soon
  • Remove Flask and djanog from docs (from code snippets)
  • Finish quick setup for fastpi for all recipes

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.