feat(auth): add account linking support for different email providers
This commit is contained in:
@@ -575,6 +575,11 @@ export function createAuth(
|
||||
// https://github.com/better-auth/better-auth/issues/5892
|
||||
account: {
|
||||
skipStateCookieCheck: true,
|
||||
accountLinking: {
|
||||
// Product requirement: signed-in users may attach OAuth identities
|
||||
// whose provider email differs from their AIRI account email.
|
||||
allowDifferentEmails: true,
|
||||
},
|
||||
},
|
||||
|
||||
socialProviders: {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { createSSRApp, ref } from 'vue'
|
||||
import { renderToString } from 'vue/server-renderer'
|
||||
|
||||
import { useLinkedAccounts } from './use-linked-accounts'
|
||||
|
||||
describe('useLinkedAccounts', () => {
|
||||
it('passes the profile page URL as the OAuth link error callback URL', async () => {
|
||||
const linkSocial = vi.fn(async () => ({
|
||||
data: { status: true, redirect: false },
|
||||
error: null,
|
||||
}))
|
||||
|
||||
const holder: {
|
||||
linkedAccounts?: ReturnType<typeof useLinkedAccounts>
|
||||
} = {}
|
||||
const app = createSSRApp({
|
||||
setup() {
|
||||
holder.linkedAccounts = useLinkedAccounts({
|
||||
client: {
|
||||
listAccounts: vi.fn(async () => ({ data: [], error: null })),
|
||||
unlinkAccount: vi.fn(async () => ({ data: null, error: null })),
|
||||
linkSocial,
|
||||
},
|
||||
isAuthenticated: ref(false),
|
||||
describeError: () => '',
|
||||
buildCallbackURL: () => 'https://auth.airi.build/ui/profile',
|
||||
messages: {
|
||||
listFailed: 'list failed',
|
||||
unlinkFailed: 'unlink failed',
|
||||
linkFailed: 'link failed',
|
||||
lastAccount: 'last account',
|
||||
unlinked: provider => `${provider} unlinked`,
|
||||
linkStarted: provider => `${provider} link started`,
|
||||
},
|
||||
})
|
||||
|
||||
return () => null
|
||||
},
|
||||
})
|
||||
|
||||
await renderToString(app)
|
||||
|
||||
if (!holder.linkedAccounts)
|
||||
throw new Error('Expected linked accounts composable to initialize')
|
||||
|
||||
await holder.linkedAccounts.link('github', 'GitHub')
|
||||
|
||||
expect(linkSocial).toHaveBeenCalledWith({
|
||||
provider: 'github',
|
||||
callbackURL: 'https://auth.airi.build/ui/profile',
|
||||
errorCallbackURL: 'https://auth.airi.build/ui/profile',
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -196,6 +196,7 @@ export function useLinkedAccounts(args: UseLinkedAccountsArgs) {
|
||||
const { data, error: apiError } = await args.client.linkSocial({
|
||||
provider: providerId,
|
||||
callbackURL,
|
||||
errorCallbackURL: callbackURL,
|
||||
})
|
||||
if (apiError)
|
||||
throw new Error(apiError.message ?? 'linkSocial failed')
|
||||
|
||||
Reference in New Issue
Block a user