Customizing Error Handling
SuperTokens session recipie can throw the following errors:#
Unauthorised error#
- Thrown when a protected backend API is accessed without a session.
- The default bahaviour of this is to clear session tokens (if any) and send a 401 to the frontend.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
For other backend frameworks, you can follow our guide on how to spin up a separate server configured with the SuperTokens backend SDK  to authenticate requests and issue session tokens.
import SuperTokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
    supertokens: {
        connectionURI: "...",
    },
    appInfo: {
        apiDomain: "...",
        appName: "...",
        websiteDomain: "..."
    },
    recipeList: [
        Session.init({
            errorHandlers: {
                onUnauthorised: async (message, request, response, userContext) => {
                    // TODO: Write your own logic and then send a 401 response to the frontend
                },
            }
        })
    ]
});
import (
    "net/http"
    "github.com/supertokens/supertokens-golang/recipe/session"
    "github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
    "github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
    supertokens.Init(supertokens.TypeInput{
        RecipeList: []supertokens.Recipe{
            session.Init(&sessmodels.TypeInput{
                ErrorHandlers: &sessmodels.ErrorHandlers{
                    OnUnauthorised: func(message string, req *http.Request, res http.ResponseWriter) error {
                        // TODO: Write your own logic and then send a 401 response to the frontend
                        return nil
                    },
                },
            }),
        },
    })
}
from supertokens_python import init, InputAppInfo
from supertokens_python.recipe import session
from supertokens_python.framework import BaseRequest, BaseResponse
async def unauthorised_callback(req: BaseRequest, err: str, response: BaseResponse):
    # TODO: Write your own logic and then send a 401 response to the frontend
    return response
init(
    app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."),
    framework='...', 
    recipe_list=[
        session.init(
            error_handlers=session.InputErrorHandlers(
                on_unauthorised=unauthorised_callback
            )
        )
    ]
)
Invalid claim error#
- Thrown when a protected backend API is accessed with a session that doesn't pass the claim validators
- The default bahaviour of this is to send a 403 to the frontend with the errors includes in the body.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
For other backend frameworks, you can follow our guide on how to spin up a separate server configured with the SuperTokens backend SDK  to authenticate requests and issue session tokens.
import SuperTokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
    supertokens: {
        connectionURI: "...",
    },
    appInfo: {
        apiDomain: "...",
        appName: "...",
        websiteDomain: "..."
    },
    recipeList: [
        Session.init({
            errorHandlers: {
                onInvalidClaim: async (validatorErrors, request, response, userContext) => {
                    // TODO: Write your own logic and then send a 403 response to the frontend
                },
            }
        })
    ]
});
import (
    "net/http"
    "github.com/supertokens/supertokens-golang/recipe/session"
    "github.com/supertokens/supertokens-golang/recipe/session/claims"
    "github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
    "github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
    supertokens.Init(supertokens.TypeInput{
        RecipeList: []supertokens.Recipe{
            session.Init(&sessmodels.TypeInput{
                ErrorHandlers: &sessmodels.ErrorHandlers{
                    OnInvalidClaim: func(validationErrors []claims.ClaimValidationError, req *http.Request, res http.ResponseWriter) error {
                        // TODO: Write your own logic and then send a 403 response to the frontend
                        return nil
                    },
                },
            }),
        },
    })
}
from supertokens_python import init, InputAppInfo
from supertokens_python.recipe import session
from supertokens_python.recipe.session.exceptions import ClaimValidationError
from supertokens_python.framework import BaseRequest, BaseResponse
from typing import List
async def invalid_claim_callback(req: BaseRequest, invalid_claims: List[ClaimValidationError], response: BaseResponse):
    # TODO: Write your own logic and then send a 403 response to the frontend
    return response
init(
    app_info=InputAppInfo(
        api_domain="...", app_name="...", website_domain="..."),
    framework='...',  
    recipe_list=[
        session.init(
            error_handlers=session.InputErrorHandlers(
                on_invalid_claim=invalid_claim_callback
            )
        )
    ]
)
Token theft detected#
- Thrown when a session hijacking attempt has been detected.
- We detect this using rotating refresh tokens.
- The default behaviour of this is to revoke the session and send a 401to the frontend.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
For other backend frameworks, you can follow our guide on how to spin up a separate server configured with the SuperTokens backend SDK  to authenticate requests and issue session tokens.
import SuperTokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
    supertokens: {
        connectionURI: "...",
    },
    appInfo: {
        apiDomain: "...",
        appName: "...",
        websiteDomain: "..."
    },
    recipeList: [
        Session.init({
            errorHandlers: {
                onTokenTheftDetected: async (sessionHandle, userId, req, res, userContext) => {
                    // TODO: Write your own logic and then send a 401 response to the frontend
                },
            }
        })
    ]
});
import (
    "net/http"
    "github.com/supertokens/supertokens-golang/recipe/session"
    "github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
    "github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
    supertokens.Init(supertokens.TypeInput{
        RecipeList: []supertokens.Recipe{
            session.Init(&sessmodels.TypeInput{
                ErrorHandlers: &sessmodels.ErrorHandlers{
                    OnTokenTheftDetected: func(sessionHandle, userID string,
                        req *http.Request, res http.ResponseWriter) error {
                        // TODO: Write your own logic and then send a 401 response to the frontend
                        return nil
                    },
                },
            }),
        },
    })
}
from supertokens_python import init, InputAppInfo
from supertokens_python.recipe import session
from supertokens_python.framework import BaseRequest, BaseResponse
async def token_theft_detected_callback(req: BaseRequest, session_handle: str, user_id: str, response: BaseResponse):
    # TODO: Write your own logic and then send a 401 response to the frontend
    return response
init(
    app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."),
    
    framework='...', 
    recipe_list=[
        session.init(
            error_handlers=session.InputErrorHandlers(
                on_token_theft_detected=token_theft_detected_callback
            )
        )
    ]
)
Try Refresh Token#
- Thrown when the access token is expired or invalid. This can also be thrown from the session refresh endpoint if multiple access tokens are present in the request cookies.
- The default bahaviour of this is to send a 401 to the frontend.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
For other backend frameworks, you can follow our guide on how to spin up a separate server configured with the SuperTokens backend SDK  to authenticate requests and issue session tokens.
import SuperTokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
    supertokens: {
        connectionURI: "...",
    },
    appInfo: {
        apiDomain: "...",
        appName: "...",
        websiteDomain: "..."
    },
    recipeList: [
        Session.init({
            errorHandlers: {
                onTryRefreshToken: async (message, request, response, userContext) => {
                    // TODO: Write your own logic and then send a 401 response to the frontend
                },
            }
        })
    ]
});
import (
    "net/http"
    "github.com/supertokens/supertokens-golang/recipe/session"
    "github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
    "github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
    supertokens.Init(supertokens.TypeInput{
        RecipeList: []supertokens.Recipe{
            session.Init(&sessmodels.TypeInput{
                ErrorHandlers: &sessmodels.ErrorHandlers{
                    OnTryRefreshToken: func(message string, req *http.Request, res http.ResponseWriter) error {
                        // TODO: Write your own logic and then send a 401 response to the frontend
                        return nil
                    },
                },
            }),
        },
    })
}
from supertokens_python import init, InputAppInfo
from supertokens_python.recipe import session
from supertokens_python.framework import BaseRequest, BaseResponse
async def try_refresh_callback(req: BaseRequest, err: str, response: BaseResponse):
    # TODO: Write your own logic and then send a 401 response to the frontend
    return response
init(
    app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."),
    framework='...', 
    recipe_list=[
        session.init(
            error_handlers=session.InputErrorHandlers(
                on_try_refresh_token=try_refresh_callback
            )
        )
    ]
)
Clear Duplicate Session Cookies#
- Thrown when the refresh session API clears session cookies from the olderCookieDomainbecause multiple access tokens were found in the request cookies. See this issue for more information.
- The default bahaviour of this is to send a 200 to the frontend.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
For other backend frameworks, you can follow our guide on how to spin up a separate server configured with the SuperTokens backend SDK  to authenticate requests and issue session tokens.
import SuperTokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
    supertokens: {
        connectionURI: "...",
    },
    appInfo: {
        apiDomain: "...",
        appName: "...",
        websiteDomain: "..."
    },
    recipeList: [
        Session.init({
            errorHandlers: {
                onClearDuplicateSessionCookies: async (message, request, response, userContext) => {
                    // TODO: Write your own logic and then send a 200 response to the frontend
                },
            }
        })
    ]
});
import (
    "net/http"
    "github.com/supertokens/supertokens-golang/recipe/session"
    "github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
    "github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
    supertokens.Init(supertokens.TypeInput{
        RecipeList: []supertokens.Recipe{
            session.Init(&sessmodels.TypeInput{
                ErrorHandlers: &sessmodels.ErrorHandlers{
                    OnClearDuplicateSessionCookies: func(message string, req *http.Request, res http.ResponseWriter) error {
                        // TODO: Write your own logic and then send a 200 response to the frontend
                        return nil
                    },
                },
            }),
        },
    })
}
from supertokens_python import init, InputAppInfo
from supertokens_python.recipe import session
from supertokens_python.framework import BaseRequest, BaseResponse
async def on_clear_duplication_session_cookies_callback(req: BaseRequest, err: str, response: BaseResponse):
    # TODO: Write your own logic and then send a 200 response to the frontend
    return response
init(
    app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."),
    framework='...', 
    recipe_list=[
        session.init(
            error_handlers=session.InputErrorHandlers(
                on_clear_duplicate_session_cookies=on_clear_duplication_session_cookies_callback
            )
        )
    ]
)