Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Email password feature branch #293

Merged
merged 33 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e8a65bf
added functions and updateed interface for email-pasword-login
iresharma Feb 27, 2023
dc5f099
versions updated
iresharma Feb 27, 2023
1776a53
versions updated
iresharma Feb 27, 2023
bb515f4
changed init function to accept None for api_key
iresharma Feb 27, 2023
ba0a2b9
api implementation for email-password login for dashboard recipe
iresharma Feb 27, 2023
6f991c3
signout auth_mode fix
iresharma Feb 27, 2023
eeb537e
formatting fixes
iresharma Feb 27, 2023
59d76b1
Merge branch 'feat/email-password-login' into interface-changes
iresharma Feb 27, 2023
1c140fc
merge commit
iresharma Feb 27, 2023
7d0ad5f
changelog edited
iresharma Feb 27, 2023
e7a0567
merge commit
iresharma Feb 27, 2023
c6cf432
Merge branch 'interface-changes' into api-logic-implementation
iresharma Feb 27, 2023
aea0372
Merge branch 'email-password-feature-branch' into feat/email-password…
iresharma Feb 27, 2023
8beebf4
Merge pull request #289 from supertokens/feat/email-password-login
nkshah2 Feb 27, 2023
11a2feb
Merge pull request #290 from supertokens/interface-changes
nkshah2 Feb 27, 2023
38055c5
add messages to signin and refactored signout
iresharma Feb 28, 2023
13aa6a1
good practice chamges
iresharma Mar 1, 2023
f0788d2
api_key made optional at recipe/__init__.py
iresharma Mar 3, 2023
d8cc66b
dashboard get edited to support authMode and self add dashboard recipe
iresharma Mar 3, 2023
e45ecb9
import fixes
iresharma Mar 3, 2023
185eded
import errors
iresharma Mar 3, 2023
7a7a031
commented auto add dashboard recipe
iresharma Mar 3, 2023
5e66b18
email password functionality added, auto initialization of dashboard …
iresharma Mar 6, 2023
5d9d560
validate_key api fixed
iresharma Mar 6, 2023
d841199
validate api check fixed
iresharma Mar 6, 2023
0fedebc
removed unecessary print
iresharma Mar 7, 2023
63eddae
added message to response for user_suspended
iresharma Mar 7, 2023
a25bc40
Merge pull request #291 from supertokens/api-logic-implementation
nkshah2 Mar 7, 2023
b698544
Update constants.py
iresharma Mar 7, 2023
94cc693
Update constants.py
iresharma Mar 7, 2023
22b113c
Update supertokens.py
iresharma Mar 7, 2023
dc3fd43
Update setup.py
iresharma Mar 7, 2023
58a8eca
reset unwanted changes
iresharma Mar 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## unreleased

## [0.12.3] - 2023-02-27
- Adds APIs and logic to the dashboard recipe to enable email password based login
## [0.12.2] - 2023-02-23
- Fix expiry time of access token cookie.

Expand Down
25 changes: 14 additions & 11 deletions coreDriverInterfaceSupported.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
{
"_comment": "contains a list of core-driver interfaces branch names that this core supports",
"versions": [
"2.9",
"2.10",
"2.11",
"2.12",
"2.13",
"2.14",
"2.15"
]
}
"_comment": "contains a list of core-driver interfaces branch names that this core supports",
"versions": [
"2.9",
"2.10",
"2.11",
"2.12",
"2.13",
"2.14",
"2.15",
"2.16",
"2.17",
"2.18"
]
}
3 changes: 2 additions & 1 deletion examples/with-flask/with-thirdpartyemailpassword/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from dotenv import load_dotenv
from flask import Flask, abort, g, jsonify
from flask_cors import CORS

from supertokens_python import (
InputAppInfo,
SupertokensConfig,
Expand All @@ -11,9 +12,9 @@
)
from supertokens_python.framework.flask import Middleware
from supertokens_python.recipe import (
emailverification,
session,
thirdpartyemailpassword,
emailverification,
)
from supertokens_python.recipe.session.framework.flask import verify_session
from supertokens_python.recipe.thirdpartyemailpassword import (
Expand Down
13 changes: 12 additions & 1 deletion supertokens_python/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,18 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
SUPPORTED_CDI_VERSIONS = ["2.9", "2.10", "2.11", "2.12", "2.13", "2.14", "2.15"]
SUPPORTED_CDI_VERSIONS = [
"2.9",
"2.10",
"2.11",
"2.12",
"2.13",
"2.14",
"2.15",
"2.16",
"2.17",
"2.18",
iresharma marked this conversation as resolved.
Show resolved Hide resolved
]
iresharma marked this conversation as resolved.
Show resolved Hide resolved
VERSION = "0.12.2"
TELEMETRY = "/telemetry"
USER_COUNT = "/users/count"
Expand Down
11 changes: 9 additions & 2 deletions supertokens_python/querier.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,18 @@ async def f(url: str) -> Response:

return await self.__send_request_helper(path, "POST", f, len(self.__hosts))

async def send_delete_request(self, path: NormalisedURLPath):
async def send_delete_request(
self, path: NormalisedURLPath, params: Union[Dict[str, Any], None] = None
):
if params is None:
params = {}

async def f(url: str) -> Response:
async with AsyncClient() as client:
return await client.delete( # type:ignore
url, headers=await self.__get_headers_with_api_version(path)
url,
params=params,
headers=await self.__get_headers_with_api_version(path),
)

return await self.__send_request_helper(path, "DELETE", f, len(self.__hosts))
Expand Down
14 changes: 8 additions & 6 deletions supertokens_python/recipe/dashboard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,20 @@

from __future__ import annotations

from typing import Optional, Callable
from typing import TYPE_CHECKING, Callable, Optional, Union

from supertokens_python import AppInfo, RecipeModule
from supertokens_python.recipe.dashboard.utils import InputOverrideConfig

from .recipe import DashboardRecipe
if TYPE_CHECKING:
from supertokens_python import AppInfo, RecipeModule
from supertokens_python.recipe.dashboard.utils import InputOverrideConfig


def init(
api_key: str,
api_key: Union[str, None] = None,
override: Optional[InputOverrideConfig] = None,
) -> Callable[[AppInfo], RecipeModule]:
# Global import for the following was avoided because of circular import errors
from .recipe import DashboardRecipe
rishabhpoddar marked this conversation as resolved.
Show resolved Hide resolved

return DashboardRecipe.init(
api_key,
override,
Expand Down
4 changes: 4 additions & 0 deletions supertokens_python/recipe/dashboard/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
# under the License.
from .api_key_protector import api_key_protector
from .dashboard import handle_dashboard_api
from .signin import handle_emailpassword_signin_api
from .signout import handle_emailpassword_signout_api
from .userdetails.user_delete import handle_user_delete
from .userdetails.user_email_verify_get import handle_user_email_verify_get
from .userdetails.user_email_verify_put import handle_user_email_verify_put
Expand Down Expand Up @@ -45,4 +47,6 @@
"handle_user_sessions_post",
"handle_user_password_put",
"handle_email_verify_token_post",
"handle_emailpassword_signin_api",
"handle_emailpassword_signout_api",
]
11 changes: 6 additions & 5 deletions supertokens_python/recipe/dashboard/api/implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,12 @@
from textwrap import dedent
from typing import TYPE_CHECKING, Any, Dict

from supertokens_python.normalised_url_domain import NormalisedURLDomain
from supertokens_python import Supertokens
from supertokens_python.normalised_url_domain import NormalisedURLDomain
from supertokens_python.normalised_url_path import NormalisedURLPath

from ..constants import DASHBOARD_API
from ..interfaces import (
APIInterface,
)
from ..interfaces import APIInterface

if TYPE_CHECKING:
from ..interfaces import APIOptions
Expand All @@ -48,7 +47,7 @@ async def dashboard_get(

connection_uri = ""
super_tokens_instance = Supertokens.get_instance()

auth_mode = options.config.auth_mode
connection_uri = super_tokens_instance.supertokens_config.connection_uri

dashboard_path = options.app_info.api_base_path.append(
Expand All @@ -65,6 +64,7 @@ async def dashboard_get(
window.staticBasePath = "${bundleDomain}/static"
window.dashboardAppPath = "${dashboardPath}"
window.connectionURI = "${connectionURI}"
window.authMode = "${authMode}"
</script>
<script defer src="${bundleDomain}/static/js/bundle.js"></script></head>
<link href="${bundleDomain}/static/css/main.css" rel="stylesheet" type="text/css">
Expand All @@ -81,6 +81,7 @@ async def dashboard_get(
bundleDomain=bundle_domain,
dashboardPath=dashboard_path,
connectionURI=connection_uri,
authMode=auth_mode,
)

self.dashboard_get = dashboard_get
56 changes: 56 additions & 0 deletions supertokens_python/recipe/dashboard/api/signin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.
#
# This software is licensed under the Apache License, Version 2.0 (the
# "License") as published by the Apache Software Foundation.
#
# You may not use this file except in compliance with the License. You may
# obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from supertokens_python.recipe.dashboard.interfaces import APIInterface, APIOptions

from supertokens_python.exceptions import raise_bad_input_exception
from supertokens_python.normalised_url_path import NormalisedURLPath
from supertokens_python.querier import Querier
from supertokens_python.utils import send_200_response


async def handle_emailpassword_signin_api(_: APIInterface, api_options: APIOptions):
body = await api_options.request.json()
if body is None:
raise_bad_input_exception("Please send body")
email = body.get("email")
password = body.get("password")

if email is None or not isinstance(email, str):
raise_bad_input_exception("Missing required parameter 'email'")
if password is None or not isinstance(password, str):
raise_bad_input_exception("Missing required parameter 'password'")
response = await Querier.get_instance().send_post_request(
NormalisedURLPath("/recipe/dashboard/signin"),
{"email": email, "password": password},
)

if "status" in response and response["status"] == "OK":
return send_200_response(
{"status": "OK", "sessionId": response["sessionId"]}, api_options.response
)
if "status" in response and response["status"] == "INVALID_CREDENTIALS_ERROR":
return send_200_response(
{"status": "INVALID_CREDENTIALS_ERROR"},
api_options.response,
)
if "status" in response and response["status"] == "USER_SUSPENDED_ERROR":
return send_200_response(
{"status": "USER_SUSPENDED_ERROR", "message": response["message"]},
api_options.response,
)
43 changes: 43 additions & 0 deletions supertokens_python/recipe/dashboard/api/signout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.
#
# This software is licensed under the Apache License, Version 2.0 (the
# "License") as published by the Apache Software Foundation.
#
# You may not use this file except in compliance with the License. You may
# obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from supertokens_python.recipe.dashboard.interfaces import APIInterface, APIOptions

from supertokens_python.exceptions import raise_bad_input_exception
from supertokens_python.normalised_url_path import NormalisedURLPath
from supertokens_python.querier import Querier

from ..interfaces import SignOutOK


async def handle_emailpassword_signout_api(
_: APIInterface, api_options: APIOptions
) -> SignOutOK:
if api_options.config.auth_mode == "api-key":
return SignOutOK()
session_id_form_auth_header = api_options.request.get_header("authorization")
if not session_id_form_auth_header:
return raise_bad_input_exception(
"Neither 'API Key' nor 'Authorization' header was found"
)
session_id_form_auth_header = session_id_form_auth_header.split()[1]
await Querier.get_instance().send_delete_request(
NormalisedURLPath("/recipe/dashboard/session"),
{"sessionId": session_id_form_auth_header},
)
return SignOutOK()
20 changes: 7 additions & 13 deletions supertokens_python/recipe/dashboard/api/validate_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,19 @@
)

from supertokens_python.utils import (
default_user_context,
send_200_response,
send_non_200_response_with_message,
)

from ..utils import validate_api_key


async def handle_validate_key_api(
api_implementation: APIInterface, api_options: APIOptions
_api_implementation: APIInterface, api_options: APIOptions
):
_ = api_implementation

should_allow_accesss = await api_options.recipe_implementation.should_allow_access(
api_options.request,
api_options.config,
default_user_context(api_options.request),
)
if should_allow_accesss is False:
return send_non_200_response_with_message(
"Unauthorized access", 401, api_options.response
)
is_valid_key = validate_api_key(api_options.request, api_options.config)

return send_200_response({"status": "OK"}, api_options.response)
if is_valid_key:
return send_200_response({"status": "OK"}, api_options.response)
return send_non_200_response_with_message("Unauthorised", 401, api_options.response)
2 changes: 2 additions & 0 deletions supertokens_python/recipe/dashboard/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@
USER_SESSION_API = "/api/user/sessions"
USER_PASSWORD_API = "/api/user/password"
USER_EMAIL_VERIFY_TOKEN_API = "/api/user/email/verify/token"
EMAIL_PASSWORD_SIGN_IN = "/api/signin"
EMAIL_PASSSWORD_SIGNOUT = "/api/signout"
12 changes: 10 additions & 2 deletions supertokens_python/recipe/dashboard/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@
from supertokens_python.recipe.session.interfaces import SessionInformationResult
from supertokens_python.types import User

from ...supertokens import AppInfo
from ...types import APIResponse
from .utils import DashboardConfig, UserWithMetadata

if TYPE_CHECKING:
from supertokens_python.framework import BaseRequest, BaseResponse

from ...supertokens import AppInfo
from .utils import DashboardConfig, UserWithMetadata


class SessionInfo:
def __init__(self, info: SessionInformationResult) -> None:
Expand Down Expand Up @@ -285,3 +286,10 @@ def __init__(self, error: str) -> None:

def to_json(self) -> Dict[str, Any]:
return {"status": self.status, "error": self.error}


class SignOutOK(APIResponse):
status: str = "OK"

def to_json(self):
return {"status": self.status}
Loading