© 2026 Hedgehog Software, LLC

TwitterGitHubDiscord
More
CommunitiesDocsAboutTermsPrivacy
Search
Star
Setup for Free
SupabaseS
Supabase•13mo ago•
2 replies
WreckNoFear

Password reset not working on mobile

Hi, I'm using supabase reset password for email. If I click the link sent in the email on my desktop (I've tested with Gmail web and Outlook app), it redirects as its supposed to and works with no issue. If I click this link on my iPhone, (I've tested using default Mail app and Gmail app) I get sent to my
/auth/error
/auth/error
page which will only happen if there is no code returned from this link or if an error occurs (I'm using the default provided supabase route handler as below).

    const { error } = await supabase.auth.resetPasswordForEmail(data.email, {
      redirectTo: process.env.NEXT_PUBLIC_URL + '/auth/callback/provider?next=/auth/reset-password',
    });
    const { error } = await supabase.auth.resetPasswordForEmail(data.email, {
      redirectTo: process.env.NEXT_PUBLIC_URL + '/auth/callback/provider?next=/auth/reset-password',
    });


/auth/callback/provider route handler:
export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url);
  const code = searchParams.get('code');
  const next = searchParams.get('next') ?? '/';

  if (code) {
    const supabase = await createSupabaseServerClient();
    const { error } = await supabase.auth.exchangeCodeForSession(code);

    if (!error) {
      const forwardedHost = request.headers.get('x-forwarded-host');
      const isLocalEnv = process.env.NODE_ENV === 'development';
      if (isLocalEnv) {
        return NextResponse.redirect(`${origin}${next}`);
      } else if (forwardedHost) {
        return NextResponse.redirect(`https://${forwardedHost}${next}`);
      } else {
        return NextResponse.redirect(`${origin}${next}`);
      }
    }
  }
  return NextResponse.redirect(`${origin}/auth/error`);
}
export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url);
  const code = searchParams.get('code');
  const next = searchParams.get('next') ?? '/';

  if (code) {
    const supabase = await createSupabaseServerClient();
    const { error } = await supabase.auth.exchangeCodeForSession(code);

    if (!error) {
      const forwardedHost = request.headers.get('x-forwarded-host');
      const isLocalEnv = process.env.NODE_ENV === 'development';
      if (isLocalEnv) {
        return NextResponse.redirect(`${origin}${next}`);
      } else if (forwardedHost) {
        return NextResponse.redirect(`https://${forwardedHost}${next}`);
      } else {
        return NextResponse.redirect(`${origin}${next}`);
      }
    }
  }
  return NextResponse.redirect(`${origin}/auth/error`);
}


Sometimes I can see this error appearing in the URL:
#error=access_denied&error_code=otp_expired&error_description=Email+link+is+invalid+or+has+expired
#error=access_denied&error_code=otp_expired&error_description=Email+link+is+invalid+or+has+expired


I just don't understand why it works on desktop and not on mobile. Any help appreciated.
Supabase banner
SupabaseJoin
Supabase gives you the tools, documentation, and community that makes managing databases, authentication, and backend infrastructure a lot less overwhelming.
45,816Members
Resources
Was this page helpful?

Similar Threads

Recent Announcements

Similar Threads

Password Reset redirectTo Parameter Not Working
SupabaseSSupabase / help-and-questions
6mo ago
Reset Password flow confusion/not working
SupabaseSSupabase / help-and-questions
3y ago
Reset password link not working as expected
SupabaseSSupabase / help-and-questions
4mo ago
Password Reset and Email Verification on mobile only app
SupabaseSSupabase / help-and-questions
3y ago