diff --git a/src/GoTrueClient.ts b/src/GoTrueClient.ts index 94247672c..3f5aa472f 100644 --- a/src/GoTrueClient.ts +++ b/src/GoTrueClient.ts @@ -11,6 +11,7 @@ import { isAuthApiError, isAuthError, isAuthRetryableFetchError, + isAuthSessionMissingError, } from './lib/errors' import { Fetch, @@ -1194,6 +1195,15 @@ export default class GoTrueClient { }) } catch (error) { if (isAuthError(error)) { + if (isAuthSessionMissingError(error)) { + // JWT contains a `session_id` which does not correspond to an active + // session in the database, indicating the user is signed out. + + await this._removeSession() + await removeItemAsync(this.storage, `${this.storageKey}-code-verifier`) + await this._notifyAllSubscribers('SIGNED_OUT', null) + } + return { data: { user: null }, error } } diff --git a/src/lib/errors.ts b/src/lib/errors.ts index 1d35694f7..c9ab5746f 100644 --- a/src/lib/errors.ts +++ b/src/lib/errors.ts @@ -69,6 +69,10 @@ export class AuthSessionMissingError extends CustomAuthError { } } +export function isAuthSessionMissingError(error: any): error is AuthSessionMissingError { + return isAuthError(error) && error.name === 'AuthSessionMissingError' +} + export class AuthInvalidTokenResponseError extends CustomAuthError { constructor() { super('Auth session or user missing', 'AuthInvalidTokenResponseError', 500, undefined) diff --git a/src/lib/fetch.ts b/src/lib/fetch.ts index 2605f023e..632d6729a 100644 --- a/src/lib/fetch.ts +++ b/src/lib/fetch.ts @@ -91,6 +91,11 @@ export async function handleError(error: unknown) { error.status, data.weak_password?.reasons || [] ) + } else if (errorCode === 'session_not_found') { + // The `session_id` inside the JWT does not correspond to a row in the + // `sessions` table. This usually means the user has signed out, has been + // deleted, or their session has somehow been terminated. + throw new AuthSessionMissingError() } throw new AuthApiError(_getErrorMessage(data), error.status || 500, errorCode)