supabase / supabase-js

An isomorphic Javascript client for Supabase. Query your Supabase database, subscribe to realtime events, upload and download files, browse typescript examples, invoke postgres functions via rpc, invoke supabase edge functions, query pgvector.
https://supabase.com
MIT License
3.24k stars 266 forks source link

React Native - Expo, Password Reset, redirect URL and Exchange authorization code. #843

Open AHMED-5G opened 1 year ago

AHMED-5G commented 1 year ago

Bug report

I am encountering difficulties with the password reset feature in while developing a React Native Expo application. The password reset is not functioning as expected, and I am experiencing inconsistent behavior with the redirect URL. Additionally, how to handle reset password after redirect what is code ? Screenshot from 2023-08-23 02-16-41

Actual Behavior

// The code is retrieved from the query parameter - use whichever mechanism is recommended // for your app/framework. This is just an example. const code = url.searchParams.get('code')

// call the Supabase API to exchange the code for a session await supabase.auth.exchangeCodeForSession(code)

However, the query parameter looks like this:
`exp://127.0.0.1:8081/--/resetPassword#access_token=123&expires_in=3600&refresh_token=123&token_type=bearer&type=recovery"`

- Redirect URLs
![Screenshot from 2023-08-23 01-20-06](https://github.com/supabase/supabase/assets/75797110/d0a5f8cb-82de-429c-8775-87f55cf000e6)

- Code snippets:
`supabase.ts`
```ts
import "react-native-url-polyfill/auto";
import * as SecureStore from "expo-secure-store";
import { createClient } from "@supabase/supabase-js";
import { SUPABASE_ANON_KEY } from "@env";
import { SupabaseAuthClientOptions } from "@supabase/supabase-js/dist/module/lib/types";

const ExpoSecureStoreAdapter = {
  getItem: (key: string) => {
    return SecureStore.getItemAsync(key);
  },
  setItem: (key: string, value: string) => {
    SecureStore.setItemAsync(key, value);
  },
  removeItem: (key: string) => {
    SecureStore.deleteItemAsync(key);
  },
};

const supabaseUrl = "https://bbrkeceesipzffkdvfpd.supabase.co";
const supabaseAnonKey = SUPABASE_ANON_KEY;

export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
  auth: {
    storage: ExpoSecureStoreAdapter as SupabaseAuthClientOptions["storage"],
    autoRefreshToken: true,
    persistSession: true,
    detectSessionInUrl: false,
  },
});

LoginScreen.ts

    const resetPassword = async (email: string) => {

      const resetPasswordURL = Linking.createURL("resetPassword"); 

      const { data, error } = await supabase.auth.resetPasswordForEmail(email, {
        redirectTo: resetPasswordURL,
      });
    };

Screenshots

inspector

System information

j4w8n commented 1 year ago

To take advantage of the exchange code route method, you need to set auth > flowType option to pkce for your supabase client

sannajammeh commented 1 year ago

However, the query parameter looks like this: exp://127.0.0.1:8081/--/resetPassword#access_token=123&expires_in=3600&refresh_token=123&token_type=bearer&type=recovery"

Multiple problems here:

  1. As @j4w8n mentioned you need flowtype set to pkce.
  2. For non PKCE flow you need to replace the # with ? to be able to extract it from the query.

Augment this for PKCE flow once you have that enabled. You also need URL polyfill to be installed.

const parsedUrl = url_with_code_as_hashtag.replace("#", "?");
const url = new URL(parsedUrl);
const access_token = url.searchParams.get("access_token");
const refresh_token = url.searchParams.get("refresh_token");

// Handle code exchanges

I'm using Supabase without PKCE with success from the above code.

j4w8n commented 1 year ago

However, the query parameter looks like this: exp://127.0.0.1:8081/--/resetPassword#access_token=123&expires_in=3600&refresh_token=123&token_type=bearer&type=recovery"

Multiple problems here:

  1. As @j4w8n mentioned you need flowtype set to pkce.
  2. For non PKCE flow you need to replace the # with ? to be able to extract it from the query.

Augment this for PKCE flow once you have that enabled. You also need URL polyfill to be installed.

const parsedUrl = url_with_code_as_hashtag.replace("#", "?");
const url = new URL(parsedUrl);
const access_token = url.searchParams.get("access_token");
const refresh_token = url.searchParams.get("refresh_token");

// Handle code exchanges

I'm using Supabase without PKCE with success from the above code.

That is by design. The supabase client, in non-pkce mode, should be handling that scenario automatically.

sannajammeh commented 1 year ago

That is by design. The supabase client, in non-pkce mode, should be handling that scenario automatically.

Yes I'm aware. Not Supabase problem I'm mentioning.