@amplication/plugin-auth-supertokens
Use supertokens for authentication in the service generated by Amplication.
Purpose
This plugin adds the required code to use supertokens for authentication in the service generated by Amplication.
Supertokens is an open source Auth0 alternative. It provides 3 components that need to be setup:
the frontend SDK, the backend SDK, and the SuperTokens core service. For more information on
these, you can check the supertokens docs (https://supertokens.com/docs/emailpassword/introduction#architecture).
Authentication methods are setup with the use of recipes.
This plugin generates code for the email password recipe that allows users to be authenticated with
their emails and passwords, the passwordless recipe that allows users to be authenticated with only their
phone numbers or emails, the third party recipe that allows users to be authenticated using third party
providers like Google, phone password recipe that allows users to be authenticated using their
phone number and passwords and combinations of third party with other recipes that SuperTokens provides
guides for on their guides page: https://supertokens.com/docs/guides.
It updates the following parts:
- Adds the required dependencies to
package.json
, both for the server and the admin UI. - Adds the required environment variables to
.env
, both for the server and the admin UI. - Adds code for the authentication based on supertokens backend SDK to the
auth
directory. - Adds some setup in the
connectMicroservices.ts
file. - It modifies the settings, allowing CORS only from the supertokens configured website domain.
- It disables the graphql playground and sets the CORS settings for graphql.
Amplication uses roles for authorization. The generated code integrates with this and only uses SuperTokens for authentication.
You will also need to setup the SuperTokens core which is what handles the storage of user data.
You can follow this guide: https://supertokens.com/docs/emailpassword/nestjs/guide#10-setup-the-supertokens-core
to set it up.
Configuration
The settings for this plugin looks like this:
export interface Settings {
apiDomain: string;
appName: string;
websiteDomain: string;
websiteBasePath: string;
apiBasePath: string;
connectionUri: string;
apiGatewayPath: string;
apiKey: string;
supertokensIdFieldName: string;
recipe: {
};
}
The apiDomain
specified will become the SUPERTOKENS_API_DOMAIN
environment variable in the server's
.env file and REACT_APP_SUPERTOKENS_API_DOMAIN
in the admin UI's .env file. This will be used as the
apiDomain
value in the SuperTokens appInfo configuration.
The appName
specified will become the SUPERTOKENS_APP_NAME
environment variable in the server's .env
file and the REACT_APP_SUPERTOKENS_APP_NAME
in the admin UI's .env file. This will be used as the
appName
value in the SuperTokens appInfo configuration.
The websiteDomain
specified will become the SUPERTOKENS_WEBSITE_DOMAIN
environment variable in the
server's .env file and the REACT_APP_SUPERTOKENS_WEBSITE_DOMAIN
environment variable in the admin UI's .env
file. The will be used as the websiteDomain
value in the SuperTokens appInfo configuration.
The websiteBasePath
specified will become the SUPERTOKENS_WEBSITE_BASE_PATH
environment variable in the
server's .env file. This will be used as the websiteBasePath
value in the server SuperTokens appInfo
configuration.
The apiBasePath
specified will become the SUPERTOKENS_API_BASE_PATH
environment variable in the server's
.env file and the REACT_APP_SUPERTOKENS_API_BASE_PATH
in the admin UI's .env file. This will be used as the
apiBasePath
value in the SuperTokens appInfo configuration.
The connectionUri
specified will become the SUPERTOKENS_CONNECTION_URI
environment variable in the
server's .env file. This will be used as the connectionUri
value in the server's SuperTokens
configuration.
The apiGatewayPath
specified will become the SUPERTOKENS_API_GATEWAY_PATH
environment variable in the
server's .env file. This will be used as the apiGatewatPath
value in the server's appInfo SuperTokens
configuration.
The apiKey
specified will become the SUPERTOKENS_API_KEY
environment variable in the server's .env file.
This will be used as the apiKey
value in the server's SuperTokens configuration.
The supertokensIdFieldName
is the name of the field that will hold a user's SuperTokens ID in the auth entity. An error will be thrown if the field does not exist on the auth entity.
The recipe
setting is an object whose properties depend on which authentication recipe code is being
generated for. It always has a name
property which indicates the name of the authentication method
being used.
For more info about the SuperTokens appInfo settings: https://supertokens.com/docs/emailpassword/appinfo
Email Password Configuration
For the email password recipe, the recipe setting is like:
type Recipe = {
name: "emailpassword",
};
Passwordless Configuration
The passwordless recipe setting:
type Recipe = {
name: "passwordless",
flowType: "USER_INPUT_CODE_AND_MAGIC_LINK" | "USER_INPUT_CODE" | "MAGIC_LINK",
contactMethod: "EMAIL" | "PHONE" | "EMAIL_OR_PHONE",
};
The flowType
and contactMethod
settings are used to configure SuperTokens. They are also used to determine
which code should be added in the admin UI's login page.
Third Party Configuration
The thirdparty recipe setting:
type Recipe = {
name: "thirdparty",
google?: {
clientId: string,
clientSecret?: string,
additionalConfig?: { [key: string]: string },
},
github?: {
clientId: string,
clientSecret?: string,
additionalConfig?: { [key: string]: string },
},
apple?: {
clientId: string,
clientSecret?: string,
additionalConfig?: { [key: string]: string },
},
twitter?: {
clientId: string,
clientSecret?: string,
additionalConfig?: { [key: string]: string },
},
};
The client ID, client secret and/or additional configurations specified for each desired third party
provider will be used to configure SuperTokens and to generate code for the admin UI's login page.
Third Party Email Password Configuration
The settings for the thirdpartyemailpassword is identical to that of the thirdparty settings.
Code to store emails and passwords in the local database is only generated for the emailpassword recipe.
Third Party Passwordless Configuration
The settings for this is a combination of the passwordless and the thirdparty recipe settings.
The flowType
, contactMethod
and third party provider settings have to be set.
Phone Password Configuration
This recipe doesn't require any additional configuration.
Default Configuration
If no configuration is provided the .amplicationrc.json file will use be used as the default values.
{
"apiDomain": "http://localhost:3000",
"appName": "Amplication App",
"websiteDomain": "http://localhost:3001",
"websiteBasePath": "/auth",
"apiBasePath": "/api/auth",
"connectionUri": "https://try.supertokens.com",
"apiGatewayPath": "",
"apiKey": "",
"supertokensIdFieldName": "supertokensId",
"recipe": {
"name": "emailpassword"
}
}
Scripts
build
Running npm run build
will bundle your plugin with Webpack for production.
dev
Running npm run dev
will watch your plugin's source code and automatically bundle it with every change.
test
Running npm run test
will run the plugin's test suite.
Usage
Configuration
The auth-core plugin must be installed for this plugin to work.
To configure supertokens, set the following environment variables in the server's .env file
SUPERTOKENS_CONNECTION_URI - The url link to the supertokens core.
SUPERTOKENS_APP_NAME - The name of the app.
SUPERTOKENS_API_DOMAIN - The API domain.
SUPERTOKENS_WEBSITE_DOMAIN - The website domain.
SUPERTOKENS_API_BASE_PATH - The API server base path for the auth urls.
SUPERTOKENS_WEBSITE_BASE_PATH - The website base path.
SUPERTOKENS_API_KEY - The supertokens API key.
SUPERTOKENS_API_GATEWAY_PATH - The API gateway path.
In the admin UI's .env file,
REACT_APP_SUPERTOKENS_APP_NAME corresponds to the server's SUPERTOKENS_APP_NAME
REACT_APP_SUPERTOKENS_API_DOMAIN corresponds to the server's SUPERTOKENS_API_DOMAIN
REACT_APP_SUPERTOKENS_WEBSITE_DOMAIN corresponds to the server's SUPERTOKENS_WEBSITE_DOMAIN
REACT_APP_SUPERTOKENS_API_BASE_PATH corresponds to the server's SUPERTOKENS_API_BASE_PATH
The generated code creates a new user in the DB upon user creation with the user's SuperTokens ID stored in the supertokensIdFieldName
field.
You have to manually create the corresponding supertokens user on the supertokens core and store the ID in the user's
supertokensId
field.
Server
This plugin generates the code for the initial setup of SuperTokens configuration and some utility functions
that can be used to handle user data stored on the SuperTokens core in the generated
src/auth/supertokens/supertokens.service.ts
.
The signatures of the functions that are generated depend on the selected auth recipe.
For example, when the auth recipe is emailpassword, the generated createSupertokensUser
function
looks like this:
async createSupertokensUser(
email: string,
password: string
): Promise<string> {
}
But for the passwordless recipe, the arguments will accept an email or phone number but no password.
This function, along with the other generated functions in the SuperTokens service code can be used to handle
user data on the SuperTokens core and should be customized to your specific use case.
Authorization
Although the generated code uses SuperTokens for authentication, authorization is left to the role-based
mechanism that generated Amplication code already uses. The authorization is done by a generated auth guard
in src/auth/supertokens/auth.guard.ts
.
This auth guard assumes that every user in the DB has an associated and valid SuperTokens user ID stored
in the field supertokensIdFieldName
. In all guarded endpoints, the SuperTokens session is used to retrieve
the SuperTokens user ID, which is then used to find the roles of the corresponding user in the DB.
It's these roles that are used to determine what the user is and isn't allowed to do.
What You Have To Do
Because of the way authorization works in the generated code, you have to make sure that for every user
stored in the DB, there is a corresponding valid SuperTokens user ID stored in the user's supertokensIdFieldName
.
Exactly how you should do this depends on your specific use case, so the plugin doesn't generate code for
this.
So, when a new user is created in the DB (maybe with a POST endpoint), you have to also create a user
on the SuperTokens core (you can use the generated SuperTokens service code for this) and store the
SuperTokens user ID in the DB.
Admin UI
Code is also generated for the admin UI's authentication. The code generated depends on the specific auth
recipe used. For example, if the auth recipe is emailpassword, then the generated admin UI code will have
an email and password form in the login page.
The SuperTokens frontend SDK is used for the session creation of a user.
To login a user on the admin UI, you first have to create that user on the SuperTokens core, either through
the SuperTokens backend SDK (which the generated SuperTokens service functions use) or through the
SuperTokens dashboard (which you can learn more about here: https://supertokens.com/docs/userdashboard/about).
You also have to create the user in the DB and store the SuperTokens ID of the user in the
supertokensIdFieldName
. This is necessary because SuperTokens is used for authentication and the
roles in the DB is then what is used for authorization.
You then use the details of the user to login.
For example, some steps you can follow to do this when using the emailpassword recipe:
- Customize the POST endpoint in the user controller to call
createSupertokensUser
with the
supplied email and password. - Start the admin UI and backend servers.
- Create a new user using the POST endpoint with an email and password, and all the roles the user needs
to use the admin UI pages.
- Open the admin UI page.
- Enter the email and password used to create the user.
- Click the login button.