Skip to content

Instantly share code, notes, and snippets.

@miguelespinoza
Last active September 21, 2022 19:12
Show Gist options
  • Save miguelespinoza/59d8dc57aaeae27ffac87989f06e8f0e to your computer and use it in GitHub Desktop.
Save miguelespinoza/59d8dc57aaeae27ffac87989f06e8f0e to your computer and use it in GitHub Desktop.
Support supabase v2 refresh token logic for browser extensions
const EXPIRY_MARGIN = 10 * 1000;
class Auth {
initialize = async () => {
// Get the latest session, token may be refreshed
const { data, error } = await supabase.auth.getSession();
if (error) throw error;
if (data.session?.expires_at) {
// Create an alarm 10 seconds before token expiring
browser.alarms.create('token-expired', {
when: data.session.expires_at * 1000 - EXPIRY_MARGIN,
});
}
};
refreshToken = async () => {
// Wrap in network retry timeout similar to https://github.com/supabase/gotrue-js/blob/master/src/GoTrueClient.ts#L761-L770
await this._callRefreshToken();
};
private _callRefreshToken = async () => {
const { data, error } = await supabase.auth.getSession();
if (error) throw error;
if (data.session) {
const { data: newSessionData, error: newSessionError } = await supabase.auth.setSession(data.session.refresh_token);
if (newSessionError) throw newSessionError;
if (newSessionData.session?.expires_at) {
// Create a new alarm for the next token expiration
browser.alarms.create('token-expired', {
when: newSessionData.session.expires_at * 1000 - EXPIRY_MARGIN,
});
}
}
};
}
export default new Auth();
browser.alarms.onAlarm.addListener(async (alarm) => {
if (alarm.name === 'token-expired) {
await Auth.refreshToken();
return;
}
});
// Call in your initialization logic
Auth.initialize();
import { createClient, SupportedStorage } from '@supabase/supabase-js';
import { browser } from 'webextension-polyfill-ts';
const supabaseUrl = process.env.SUPABASE_URL as string;
const supabaseKey = process.env.SUPABASE_PUBLIC_KEY as string;
const browserStorageInterface: SupportedStorage = {
async getItem(key: string): Promise<string | null> {
const storage = await browser.storage.local.get(key);
return storage?.[key];
},
async setItem(key: string, value: string): Promise<void> {
await browser.storage.local.set({
[key]: value,
});
},
async removeItem(key: string): Promise<void> {
await browser.storage.local.remove(key);
},
};
const supabase = createClient(supabaseUrl, supabaseKey, {
auth: {
persistSession: true,
// This configuration is important, since now the extension is reponsible for refreshing the token
autoRefreshToken: false,
detectSessionInUrl: false,
storage: browserStorageInterface,
},
});
export default supabase;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment