Skip to content

Commit c6fbbd1

Browse files
committed
feat: add third-party auth support
1 parent cb7b046 commit c6fbbd1

File tree

4 files changed

+51
-6
lines changed

4 files changed

+51
-6
lines changed

src/SupabaseClient.ts

+26-6
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export default class SupabaseClient<
5151
protected storageKey: string
5252
protected fetch?: Fetch
5353
protected changedAccessToken?: string
54+
protected accessToken?: () => Promise<string>
5455

5556
protected headers: Record<string, string>
5657

@@ -95,11 +96,24 @@ export default class SupabaseClient<
9596
this.storageKey = settings.auth.storageKey ?? ''
9697
this.headers = settings.global.headers ?? {}
9798

98-
this.auth = this._initSupabaseAuthClient(
99-
settings.auth ?? {},
100-
this.headers,
101-
settings.global.fetch
102-
)
99+
if (!settings.accessToken) {
100+
this.auth = this._initSupabaseAuthClient(
101+
settings.auth ?? {},
102+
this.headers,
103+
settings.global.fetch
104+
)
105+
} else {
106+
this.accessToken = settings.accessToken
107+
108+
this.auth = new Proxy<SupabaseAuthClient>({} as any, {
109+
get: (prop) => {
110+
throw new Error(
111+
`@supabase/supabase-js: Supabase Client is configured with the accessToken option, accessing supabase.auth.${prop} is not possible`
112+
)
113+
},
114+
})
115+
}
116+
103117
this.fetch = fetchWithAuth(supabaseKey, this._getAccessToken.bind(this), settings.global.fetch)
104118

105119
this.realtime = this._initRealtimeClient({ headers: this.headers, ...settings.realtime })
@@ -109,7 +123,9 @@ export default class SupabaseClient<
109123
fetch: this.fetch,
110124
})
111125

112-
this._listenForAuthEvents()
126+
if (!settings.accessToken) {
127+
this._listenForAuthEvents()
128+
}
113129
}
114130

115131
/**
@@ -244,6 +260,10 @@ export default class SupabaseClient<
244260
}
245261

246262
private async _getAccessToken() {
263+
if (this.accessToken) {
264+
return await this.accessToken()
265+
}
266+
247267
const { data } = await this.auth.getSession()
248268

249269
return data.session?.access_token ?? null

src/lib/helpers.ts

+1
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,6 @@ export function applySettingDefaults<
5454
...DEFAULT_GLOBAL_OPTIONS,
5555
...globalOptions,
5656
},
57+
accessToken: options.accessToken ?? undefined,
5758
}
5859
}

src/lib/types.ts

+12
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,18 @@ export type SupabaseClientOptions<SchemaName> = {
6666
*/
6767
headers?: Record<string, string>
6868
}
69+
/**
70+
* Optional function for using a third-party authentication system with
71+
* Supabase. The function should return an access token or ID token (JWT) by
72+
* obtaining it from the third-party auth client library. Note that this
73+
* function may be called concurrently and many times. Use memoization and
74+
* locking techniques if this is not supported by the client libraries.
75+
*
76+
* When set, the `auth` namespace of the Supabase client cannot be used.
77+
* Create another client if you wish to use Supabase Auth and third-party
78+
* authentications concurrently in the same application.
79+
*/
80+
accessToken?: () => Promise<string>
6981
}
7082

7183
export type GenericTable = {

test/client.test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ const KEY = 'some.fake.key'
77

88
const supabase = createClient(URL, KEY)
99

10+
test('it should create a client with third-party auth accessToken', async () => {
11+
const client = createClient(URL, KEY, {
12+
accessToken: async () => {
13+
return 'jwt'
14+
},
15+
})
16+
17+
expect(() => client.auth.getUser()).toThrowError(
18+
'@supabase/supabase-js: Supabase Client is configured with the accessToken option, accessing supabase.auth.getUser is not possible'
19+
)
20+
})
21+
1022
test('it should create the client connection', async () => {
1123
expect(supabase).toBeDefined()
1224
expect(supabase).toBeInstanceOf(SupabaseClient)

0 commit comments

Comments
 (0)