APIs override
Overview
Overriding APIs allows you to take full control of what happens when the frontend SDK calls the backend authentication endpoints. You can send analytics events, syncronize additional information in your own database, or adjust the request input.
General example
Like with the functions override feature, you need to call the original implementation reference to avoid any errors in the authentication flow.
import SuperTokens from "supertokens-node";
import EmailPassword from "supertokens-node/recipe/emailpassword";
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
supertokens: {
connectionURI: "...",
},
recipeList: [
Session.init({
override: {
apis: (originalImplementation) => {
return {
...originalImplementation,
// here we are only overriding the function that signs out a user
signOutPOST: async function (input) {
if (originalImplementation.signOutPOST === undefined) {
throw Error("Should never come here")
}
// TODO: some custom logic
// or call the default behaviour as show below
return await originalImplementation.signOutPOST(input);
},
// ...
// TODO: override more apis
}
}
}
}),
EmailPassword.init({
override: {
apis: (originalImplementation) => {
return {
...originalImplementation,
emailExistsGET: async function (input) {
// we can send a custom response like this:
input.options.res.setStatusCode(200); // or any other status code
input.options.res.sendJSONResponse({
message: "my custom response",
//...
})
// this return doesn't matter. But we must do it
// cause the function signature expects a response.
return {
status: "OK",
exists: false
};
}
}
}
}
})
]
});
Error management
If you want to send a custom error message from the API override function you can send a GENERAL_ERROR
response.
If you are using the pre-built UI, the response renders directly in the frontend UI. For custom UI, you can read this response and display the message in an error UI.
The next example shows you how to prevent the user from signing up unless their email is pre-approved by the application's admin.
import EmailPassword from "supertokens-node/recipe/emailpassword";
EmailPassword.init({
override: {
apis: (oI) => {
return {
...oI,
signUpPOST: async function (input) {
let email = input.formFields.find(i => i.id === "email")!.value as string;
if (emailNotAllowed(email)) {
return {
status: "GENERAL_ERROR",
message: "You are not allowed to sign up. Please contact the app's admin to get permission"
}
}
return oI.signUpPOST!(input);
}
}
}
}
})
function emailNotAllowed(email: string) {
// TODO: your impl to check if email is allowed or not
return true;
}
Disable APIs
To disable an API entirely, all you need to do is override the API implementation with undefined
.
For example, if you want to disable the sign up / sign in API from this recipe, all you do is this:
import SuperTokens from "supertokens-node";
import ThirdParty from "supertokens-node/recipe/thirdparty";
import EmailPassword from "supertokens-node/recipe/emailpassword";
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
supertokens: {
connectionURI: "...",
},
recipeList: [
EmailPassword.init({
override: {
apis: (originalImplementation) => {
return {
...originalImplementation,
signInPOST: undefined, // disable sign in with email & password
signUpPOST: undefined, // disable sign up with email & password
}
}
}
}),
ThirdParty.init({
override: {
apis: (originalImplementation) => {
return {
...originalImplementation,
signInUpPOST: undefined // disable sign in & up with third party
}
}
}
})
]
});
You then need to define your own routes that handle this API call. You can see the Frontend driver interface API spec here
Read custom request information
We use the getRequestFromUserContext
function provided by the SDK to get the request object from the user context.
import SuperTokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
Session.init({
override: {
apis: (oI) => {
return {
...oI,
signOutPOST: async (input) => {
if (oI.signOutPOST === undefined) {
throw Error("Signout API is disabled");
}
let customHeaderValue = "";
const request = SuperTokens.getRequestFromUserContext(input.userContext);
if (request !== undefined) {
customHeaderValue = request.getHeaderValue("customHeader");
} else {
/**
* This is possible if the function is triggered from the user management dashboard
*
* In this case set a reasonable default value to use
*/
customHeaderValue = "default";
}
// Perform custom logic based on the value of customHeaderValue
return oI.signOutPOST(input);
},
};
}
},
})