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

Add email password sign in to dashboard #55

Closed
rishabhpoddar opened this issue Nov 22, 2022 · 8 comments
Closed

Add email password sign in to dashboard #55

rishabhpoddar opened this issue Nov 22, 2022 · 8 comments

Comments

@rishabhpoddar
Copy link
Contributor

rishabhpoddar commented Nov 22, 2022

New core APIs:

  • create user with email password and name
  • verify email password
  • update password for user
  • get list of users
  • get JWT public signing key
  • delete user
  • does use exist

New APIs in backend SDK

  • Sign in
  • Sign out

Auth method change in backend SDK

Verify the JWT and then query the core to check if the user exists or not.

Frontend change

  • Build sign in screen
  • Building sign up screen which just shows curl commands to add a new user in the core with the right core URL.
  • Send JWT as a header
  • In sign up form, we should explain where to get the connectionURI and API key for the core.
@rishabhpoddar
Copy link
Contributor Author

rishabhpoddar commented Nov 29, 2022

MVP version

  • Sign up via curl command to the core. Curl command will take email and password of new user.
    • The curl command would require the API key if configured
    • The curl command would require direct access to the supertokens core. So if that is hosted in some instance somewhere, the dev would need to access that directly.
  • Sign in via created email and password.

V2:

  • Create only the initial user via the dashboard. No curl command needed.
  • New users will be allowed to be created via the dashboard and emails will be sent to them. Those users can then reset their passwords on the link click.

V3:

  • Multi tenancy with supertokens allowing different forms of login.

@nkshah2
Copy link
Contributor

nkshah2 commented Jan 23, 2023

Terminology

Dashboard Users: User's that are allowed to use the dashboard via email password login. These users are completely independent of the rest of the system and are only relevant to the dashboard.

General flow

Frontend -> Backend

  • Frontend receives a JWT that is stored in local storage and sent as a Bearer authorization token in all API calls
  • The frontend should display an appropriate error to the user if their credentials have been suspended (suspension explained later)
  • The backend SDK should set some information depending on whether the user is using an API key or not. Depending on whether this information is set to true the frontend should show either the API key login flow or the email password login flow. In the event that the user enabled the email password flow after already using the API key flow, the frontend should not do any special handling. When the backend receives the API key instead of a JWT the verification flow will fail and the user will get logged out

Backend -> Core

  • Backend calls core APIs during sign in to create a JWT to be sent to the frontend
  • For every API that needs auth the backend calls a verify API exposed by the Core to verify that the JWT is valid and that the user is allowed to access the dashboard

Core

  • Separate JWT signing key for the dashboard (stored in the same table as the other)
  • Dashboard users are maintained in different tables and are completely independent of normal users
  • The same API key is used to create and manage dashboard users and for normal core operations

Summary of changes

Backend SDK

1. /api/signin POST

Used to sign the user in, this API should not perform any validation on the email/password

Request:

email: string,
password: string,

Response:

{status: "OK", sessionId: string} | {status: "INVALID_CREDENTIALS_ERROR"} | {status: "USER_SUSPENDED_ERROR"}

Changes to all APIs that need auth

Request Headers:

{Authorization: "Bearer <token>"}

The absence of the header should be treated as unauthorised. Every API call should call the Core (/recipe/dashboard/jwt/verify POST) to verify the token, if the token is invalid or the user has been suspended the API should return unauthorised.

Core

Table Schema

id email is_suspended time_joined password_hash
uid (primary) string (unique) bool number string

General Notes

  • When creating users check if the feature flag for dashboard is enabled, If yes continue. If no check if the total number of users in the table (suspended or otherwise) is greater than or equal to 2. If more than 2 then the operation should not be allowed

  • During sign in if the feature flag is not enabled, check if the user is suspended and block the operation if they are.

  • All operations first call a common function. This function will check if the feature flag is enabled, if it isnt then mark all users other than the oldest 2 users in the table (based on time_joined) as suspended. If it is enabled then mark users in the table as not suspended

API Changes

ALL APIS REQUIRE AN API KEY
ALL APIS REQUIRE AN API KEY
ALL APIS REQUIRE AN API KEY

/recipe/dashboard/user POST - Used to create new dashboard users

This API should check if a user should be allowed to be created before proceeding with its logic (as explained in the general notes section)

The email should have a basic regex string validation. The password can have a medium strength regex.

Request:

email: string,
password: string,

Response:

| {status: "OK"}
| {status: "EMAIL_ALREADY_EXISTS_ERROR"}
| {status: "INVALID_EMAIL_ERROR"}
| {status: "PASSWORD_WEAK_ERROR"}
|
|
|
HTTP Status Code: 402
{status: "USER_LIMIT_REACHED_ERROR"}

/recipe/dashboard/user PUT - Used to edit the user's email or password

The same validation that happen in the POST API should apply here as well.

Request:

{
    email: string,
    newPassword?: string,
    newEmail?: string,
} | {
    userId: string,
    newPassword?: string,
    newEmail?: string,
}

This API should be a no-op if both newEmail and newPassword are missing. If both email and userId are present, the priority should be userId and the API should fail without trying with the email

Removed {status: "USER_LIMIT_REACHED_ERROR"}

Response:

| {status: "OK"}
| {status: "EMAIL_ALREADY_EXISTS_ERROR"}
| {status: "INVALID_EMAIL_ERROR"}
| {status: "PASSWORD_WEAK_ERROR"}

/recipe/dashboard/users GET - Used to get a list of all dashboard users

Request: {}

Response:

{
    users: {
        email: string,
        userId: string,
        isSuspended: bool,
    }[]
}

/recipe/dashboard/user DELETE - used to delete a specific user

Request:

| { userId: string}
| { email: string }

If both email and userId are present, the priority should be userId and the API should fail without trying with the email

Response:

{
    status: "OK",
    didUserExist: bool,
}

/recipe/dashboard/jwt/verify POST - Used to verify the JWT header sent by the frontend

This API needs to verify the JWT against the signing key for the dashboard recipe and not the JWT recipe (explained in the general notes). When verifying the JWT, ignore the expiry of the JWT (or set a really long expiry when creating it)

Verification involves a couple steps:

  • Verify the JWT with normal JWT verification
  • From the payload read the userId
  • Check if a user with that userId is present and not suspended. If the user is not present or the user is suspended, the API should return an error status

Request:

{ sessionID: string }

Response:

| {status: "OK"}
| {status: "USER_SUSPENDED_ERROR"}
| {status: "INVALID_SESSION"}

/recipe/dashboard/signin POST - Used to sign in users and issue a JWT

Request:

{
    email: string,
    password: string,
}

Response:

| {status: "OK", sessionId: string}
| {status: "INVALID_CREDENTIALS_ERROR"}
| {status: "USER_SUSPENDED_ERROR"}

@nkshah2
Copy link
Contributor

nkshah2 commented Jan 24, 2023

@jscyo @AreebKhan619 review when you can ^

@jscyo
Copy link

jscyo commented Feb 3, 2023

The dashbaord_emailpassword_users schema will not have the is_suspended field. We are removing this field because it is an extra entry in the db which will have to be managed whenever updates or deletes are done. Instead, we will find if this information is based on time_joined and the number of users.

@jscyo
Copy link

jscyo commented Feb 6, 2023

New Changes

  • Instead of creating a JWT, creating sessions for the users would be simpler. We will have a separate dashboard_user_sessions table where we map the user's userId to their session with the primary key being(userId, sessionId) with the time_created of the session.
  • The API sepc needs to be updated so that all requests which previously required a JWT in the header now will have the sessionId in the request body/param
  • Additionally, there should be an expiry time for the sessions. So if the time_created for the session is more than 30 days the session should be removed.(will need to add a cronjob for this)

@nkshah2 @AreebKhan619 The API spec will need to be updated for this

@nkshah2
Copy link
Contributor

nkshah2 commented Feb 7, 2023

@jscyo @AreebKhan619 Ive updated the spec, summary of changes:

On the backend SDKs:

  • /user/signin POST API response, token has been renamed to sessionId

Core

  • /recipe/dashboard/user PUT, the API responds with status code 402 if the user limit has been reached (@AreebKhan619 this may need special handling in the backend SDK)
  • /recipe/dashboard/verify POST, token renamed to sessionId and INVALID_JWT has been renamed to INVALID_SESSION. Added USER_SUSPENDED_ERROR to possible return status types.
  • /recipe/dashboard/signin POST: jwt renamed to sessionId. Added USER_SUSPENDED_ERROR to possible return status types

@jscyo
Copy link

jscyo commented Feb 7, 2023

Errors that require message for additional context

USER_SUSPENDED_ERROR
WEAK_PASSWORD_ERROR
USER_LIMIT_REACHED_ERROR

@nkshah2
Copy link
Contributor

nkshah2 commented Feb 21, 2023

/user PUT API should clear all current sessions of the user if the email or password or both have been modified

@jscyo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants