Custom error response using GENERAL_ERROR
status
Sometimes, you may want to send a custom error message from your API override to display to the user on the frontend. This can be done by sending the following JSON response from the API:
{
"status": "GENERAL_ERROR",
"message": "Some custom error message"
}
If you are using our pre-built ReactJS UI, the above response will render the mesage "Some custom error message"
on the frontend UI. For custom UI, you can read this response and display the message in an error UI. This response can be returned from most of the APIs exposed by the backend SDK.
Let's take an example in which we want to prevent the user from signing up unless their email is preapproved by the app's admin. For this, we will override the sign up API to check if the input email is approved or not, and if not, we prevent the sign up, and send a custom error message.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
import ThirdParty from "supertokens-node/recipe/thirdparty";
ThirdParty.init({
signInAndUpFeature: {
providers: [/* ... */]
},
override: {
functions: (oI) => {
return {
...oI,
signInUp: async function (input) {
if (emailNotAllowed(input.email)) {
// this error will signal to the API to send a GENERAL_ERROR message
throw new Error("Email not allowed");
}
return oI.signInUp(input);
}
}
},
apis: (oI) => {
return {
...oI,
signInUpPOST: async function (input) {
try {
return oI.signInUpPOST!(input);
} catch (err: any) {
if (err.message === "Email not allowed") {
return {
status: "GENERAL_ERROR",
message: "You are not allowed to sign up. Please contact the app's admin to get permission"
}
}
throw err;
}
}
}
}
}
})
function emailNotAllowed(email: string) {
// TODO: your impl to check if email is allowed or not
return true;
}
import (
"errors"
"github.com/supertokens/supertokens-golang/recipe/thirdparty"
"github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels"
"github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
thirdparty.Init(&tpmodels.TypeInput{
Override: &tpmodels.OverrideStruct{
Functions: func(originalImplementation tpmodels.RecipeInterface) tpmodels.RecipeInterface {
ogSignInUp := *originalImplementation.SignInUp
(*originalImplementation.SignInUp) = func(thirdPartyID string, thirdPartyUserID string, email string, oAuthTokens map[string]interface{}, rawUserInfoFromProvider tpmodels.TypeRawUserInfoFromProvider, tenantId string, userContext *map[string]interface{}) (tpmodels.SignInUpResponse, error) {
if emailNotAllowed(email) {
// this error will signal to the API to send a GENERAL_ERROR message
return tpmodels.SignInUpResponse{}, errors.New("Email not allowed")
}
return ogSignInUp(thirdPartyID, thirdPartyUserID, email, oAuthTokens, rawUserInfoFromProvider, tenantId, userContext)
}
return originalImplementation
},
APIs: func(originalImplementation tpmodels.APIInterface) tpmodels.APIInterface {
ogSignInUpPOST := *originalImplementation.SignInUpPOST
(*originalImplementation.SignInUpPOST) = func(provider *tpmodels.TypeProvider, input tpmodels.TypeSignInUpInput, tenantId string, options tpmodels.APIOptions, userContext *map[string]interface{}) (tpmodels.SignInUpPOSTResponse, error) {
resp, err := ogSignInUpPOST(provider, input, tenantId, options, userContext)
if err != nil {
if err.Error() == "Email not allowed" {
return tpmodels.SignInUpPOSTResponse{
GeneralError: &supertokens.GeneralErrorResponse{
Message: "You are not allowed to sign up. Please contact the app's admin to get permission",
},
}, nil
}
return tpmodels.SignInUpPOSTResponse{}, err
}
return resp, err
}
return originalImplementation
},
},
})
}
func emailNotAllowed(email string) bool {
// TODO: your impl to check email
return true
}
from supertokens_python.recipe import thirdparty
from supertokens_python.recipe.thirdparty.interfaces import (
APIInterface,
RecipeInterface,
APIOptions,
)
from supertokens_python.recipe.thirdparty.provider import Provider, RedirectUriInfo
from supertokens_python.recipe.thirdparty.types import RawUserInfoFromProvider
from typing import Any, Dict, Union, Optional
from supertokens_python.types import GeneralErrorResponse
from supertokens_python.recipe.session.interfaces import SessionContainer
def override_functions(original_implementation: RecipeInterface):
original_sign_in_up = original_implementation.sign_in_up
async def sign_in_up(
third_party_id: str,
third_party_user_id: str,
email: str,
is_verified: bool,
oauth_tokens: Dict[str, Any],
raw_user_info_from_provider: RawUserInfoFromProvider,
session: Optional[SessionContainer],
should_try_linking_with_session_user: Union[bool, None],
tenant_id: str,
user_context: Dict[str, Any],
):
if is_not_allowed(email):
# this error will signal to the API to send a GENERAL_ERROR message
raise Exception("Email not allowed")
return await original_sign_in_up(
third_party_id,
third_party_user_id,
email,
is_verified,
oauth_tokens,
raw_user_info_from_provider,
session,
should_try_linking_with_session_user,
tenant_id,
user_context,
)
original_implementation.sign_in_up = sign_in_up
return original_implementation
def override_apis(original_implementation: APIInterface):
# first we copy the original implementation
original_sign_in_up_post = original_implementation.sign_in_up_post
async def sign_in_up_post(
provider: Provider,
redirect_uri_info: Optional[RedirectUriInfo],
oauth_tokens: Optional[Dict[str, Any]],
session: Optional[SessionContainer],
should_try_linking_with_session_user: Union[bool, None],
tenant_id: str,
api_options: APIOptions,
user_context: Dict[str, Any],
):
try:
return await original_sign_in_up_post(
provider,
redirect_uri_info,
oauth_tokens,
session,
should_try_linking_with_session_user,
tenant_id,
api_options,
user_context,
)
except Exception as e:
if str(e) == "Email not allowed":
return GeneralErrorResponse(
message="You are not allowed to sign up. Please contact the app's admin to get permission"
)
raise e
original_implementation.sign_in_up_post = sign_in_up_post
return original_implementation
def is_not_allowed(email: str):
# TODO: your impl to check if the email is allowed
return True
thirdparty.init(
sign_in_and_up_feature=thirdparty.SignInAndUpFeature([]),
override=thirdparty.InputOverrideConfig(
apis=override_apis, functions=override_functions
),
)