Skip to content

Commit e04efee

Browse files
authored
feat: implement linkIdentity for oidc / native sign-in (#1096)
Adds `linkIdentity()` method which allows passing OIDC credentials. The ID token will be linked to the currently signed in user. See also: - supabase/auth#2108
1 parent cdaaa36 commit e04efee

File tree

1 file changed

+67
-1
lines changed

1 file changed

+67
-1
lines changed

packages/core/auth-js/src/GoTrueClient.ts

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2176,11 +2176,27 @@ export default class GoTrueClient {
21762176
throw error
21772177
}
21782178
}
2179+
21792180
/**
21802181
* Links an oauth identity to an existing user.
21812182
* This method supports the PKCE flow.
21822183
*/
2183-
async linkIdentity(credentials: SignInWithOAuthCredentials): Promise<OAuthResponse> {
2184+
async linkIdentity(credentials: SignInWithOAuthCredentials): Promise<OAuthResponse>
2185+
2186+
/**
2187+
* Links an OIDC identity to an existing user.
2188+
*/
2189+
async linkIdentity(credentials: SignInWithIdTokenCredentials): Promise<AuthTokenResponse>
2190+
2191+
async linkIdentity(credentials: any): Promise<any> {
2192+
if ('token' in credentials) {
2193+
return this.linkIdentityIdToken(credentials)
2194+
}
2195+
2196+
return this.linkIdentityOAuth(credentials)
2197+
}
2198+
2199+
private async linkIdentityOAuth(credentials: SignInWithOAuthCredentials): Promise<OAuthResponse> {
21842200
try {
21852201
const { data, error } = await this._useSession(async (result) => {
21862202
const { data, error } = result
@@ -2213,6 +2229,56 @@ export default class GoTrueClient {
22132229
}
22142230
}
22152231

2232+
private async linkIdentityIdToken(
2233+
credentials: SignInWithIdTokenCredentials
2234+
): Promise<AuthTokenResponse> {
2235+
return await this._useSession(async (result) => {
2236+
try {
2237+
const {
2238+
error: sessionError,
2239+
data: { session },
2240+
} = result
2241+
if (sessionError) throw sessionError
2242+
2243+
const { options, provider, token, access_token, nonce } = credentials
2244+
2245+
const res = await _request(this.fetch, 'POST', `${this.url}/token?grant_type=id_token`, {
2246+
headers: this.headers,
2247+
jwt: session?.access_token ?? undefined,
2248+
body: {
2249+
provider,
2250+
id_token: token,
2251+
access_token,
2252+
nonce,
2253+
link_identity: true,
2254+
gotrue_meta_security: { captcha_token: options?.captchaToken },
2255+
},
2256+
xform: _sessionResponse,
2257+
})
2258+
2259+
const { data, error } = res
2260+
if (error) {
2261+
return { data: { user: null, session: null }, error }
2262+
} else if (!data || !data.session || !data.user) {
2263+
return {
2264+
data: { user: null, session: null },
2265+
error: new AuthInvalidTokenResponseError(),
2266+
}
2267+
}
2268+
if (data.session) {
2269+
await this._saveSession(data.session)
2270+
await this._notifyAllSubscribers('USER_UPDATED', data.session)
2271+
}
2272+
return { data, error }
2273+
} catch (error) {
2274+
if (isAuthError(error)) {
2275+
return { data: { user: null, session: null }, error }
2276+
}
2277+
throw error
2278+
}
2279+
})
2280+
}
2281+
22162282
/**
22172283
* Unlinks an identity from a user by deleting it. The user will no longer be able to sign in with that identity once it's unlinked.
22182284
*/

0 commit comments

Comments
 (0)