@stripe/link-integrations-better-auth 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -48,6 +48,30 @@ export const authClient = createAuthClient({ plugins: [linkClient()] });
|
|
|
48
48
|
|
|
49
49
|
Default scopes are `payment_methods.agentic` and `userinfo:read`. For sign-in only, set `scopes: ['userinfo:read']` in `link(...)`. Keep `userinfo:read` when customizing scopes.
|
|
50
50
|
|
|
51
|
+
To read financial data, add `authorizationDetails`. It is sent as one JSON `authorization_details` parameter:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
link({
|
|
55
|
+
clientId: process.env.LINK_CLIENT_ID!,
|
|
56
|
+
clientSecret: process.env.LINK_CLIENT_SECRET!,
|
|
57
|
+
publishableKey: process.env.STRIPE_PUBLISHABLE_KEY!,
|
|
58
|
+
scopes: ['userinfo:read'],
|
|
59
|
+
authorizationDetails: [
|
|
60
|
+
{
|
|
61
|
+
type: 'source',
|
|
62
|
+
actions: [
|
|
63
|
+
'read_link_transactions',
|
|
64
|
+
'read_external_transactions',
|
|
65
|
+
'read_balances',
|
|
66
|
+
'read_source_details',
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
External transactions, balances, and source details require your Stripe account to be registered for Financial Connections. Request only the actions your app uses.
|
|
74
|
+
|
|
51
75
|
## Connect a wallet
|
|
52
76
|
|
|
53
77
|
After the user signs in to your app:
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export interface LinkOptions {
|
|
|
11
11
|
clientSecret: string;
|
|
12
12
|
publishableKey: string;
|
|
13
13
|
scopes?: string[];
|
|
14
|
+
/** Rich authorization requests, such as `{ type: 'source', actions }`. */
|
|
15
|
+
authorizationDetails?: ReadonlyArray<Record<string, unknown>>;
|
|
14
16
|
redirectURI?: string;
|
|
15
17
|
}
|
|
16
18
|
export declare function link(options: LinkOptions): {
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,QAAQ,mBAAmB,CAAC;IACjC,UAAU,wBAAwB,CAAC,WAAW,EAAE,OAAO;QACrD,IAAI,EAAE;YACJ,OAAO,EAAE,OAAO,IAAI,CAAC;SACtB,CAAC;KACH;CACF;AAMD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,QAAQ,mBAAmB,CAAC;IACjC,UAAU,wBAAwB,CAAC,WAAW,EAAE,OAAO;QACrD,IAAI,EAAE;YACJ,OAAO,EAAE,OAAO,IAAI,CAAC;SACtB,CAAC;KACH;CACF;AAMD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,0EAA0E;IAC1E,oBAAoB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;;;;;;QAoDnC,WAAW;;;;;;;;;;;;;;;;;QACX,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAInB;AAED,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -133,7 +133,12 @@ function link(options) {
|
|
|
133
133
|
authorizationUrl: "https://login.link.com/auth",
|
|
134
134
|
tokenUrl: "https://login.link.com/auth/token",
|
|
135
135
|
userInfoUrl: "https://api.link.com/userinfo",
|
|
136
|
-
authorizationUrlParams: {
|
|
136
|
+
authorizationUrlParams: {
|
|
137
|
+
...options.authorizationDetails?.length && {
|
|
138
|
+
authorization_details: JSON.stringify(options.authorizationDetails)
|
|
139
|
+
},
|
|
140
|
+
key: options.publishableKey
|
|
141
|
+
},
|
|
137
142
|
scopes: options.scopes ?? ["payment_methods.agentic", "userinfo:read"],
|
|
138
143
|
pkce: true,
|
|
139
144
|
accessTokenExpiresIn: 3600,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/routes.ts"],"sourcesContent":["import type { UserInfo } from '@stripe/link-sdk';\nimport type { BetterAuthPlugin } from 'better-auth';\nimport { genericOAuth } from 'better-auth/plugins/generic-oauth';\nimport { z } from 'zod';\nimport { LINK_ERROR_CODES } from './error-codes';\nimport { connectLink, disconnectLink } from './routes';\n\ndeclare module '@better-auth/core' {\n interface BetterAuthPluginRegistry<AuthOptions, Options> {\n link: {\n creator: typeof link;\n };\n }\n}\n\nconst linkProfileSchema = z.object({\n id: z.string().min(1),\n}) satisfies z.ZodType<Pick<UserInfo, 'id'>>;\n\nexport interface LinkOptions {\n clientId: string;\n clientSecret: string;\n publishableKey: string;\n scopes?: string[];\n redirectURI?: string;\n}\n\nexport function link(options: LinkOptions) {\n for (const field of ['clientId', 'clientSecret', 'publishableKey'] as const) {\n if (!options[field]?.trim()) throw new Error(`Link ${field} is required.`);\n }\n\n const oauth = genericOAuth({\n config: [\n {\n providerId: 'link',\n name: 'Link',\n clientId: options.clientId,\n clientSecret: options.clientSecret,\n redirectURI: options.redirectURI,\n authorizationUrl: 'https://login.link.com/auth',\n tokenUrl: 'https://login.link.com/auth/token',\n userInfoUrl: 'https://api.link.com/userinfo',\n authorizationUrlParams: { key: options.publishableKey },\n scopes: options.scopes ?? ['payment_methods.agentic', 'userinfo:read'],\n pkce: true,\n accessTokenExpiresIn: 3600,\n tokenEndpointAuth: {\n method: 'custom',\n customizeRequest({ body, headers }) {\n body.set('client_id', options.clientId);\n body.set('client_secret', options.clientSecret);\n headers.authorization = `Bearer ${options.publishableKey}`;\n },\n },\n accountSubject: ({ profile }) => linkProfileSchema.parse(profile).id,\n mapProfileToUser(profile) {\n return {\n name:\n profile.name ||\n [profile.first_name, profile.last_name]\n .filter((part) => typeof part === 'string')\n .join(' ') ||\n 'Link',\n };\n },\n },\n ],\n });\n\n return {\n ...oauth,\n id: 'link',\n endpoints: {\n connectLink: connectLink(),\n disconnectLink: disconnectLink(options),\n },\n $ERROR_CODES: LINK_ERROR_CODES,\n } satisfies BetterAuthPlugin;\n}\n\nexport { LINK_ERROR_CODES } from './error-codes';\n","import { BASE_ERROR_CODES } from 'better-auth';\nimport {\n APIError,\n createAuthEndpoint,\n freshSessionMiddleware,\n linkSocialAccount,\n sensitiveSessionMiddleware,\n} from 'better-auth/api';\nimport { decryptOAuthToken } from 'better-auth/oauth2';\nimport { z } from 'zod';\nimport { LINK_ERROR_CODES } from './error-codes';\nimport type { LinkOptions } from './index';\n\nexport const connectLink = () =>\n createAuthEndpoint(\n '/link/connect',\n {\n method: 'POST',\n requireHeaders: true,\n body: linkSocialAccount.options.body.omit({\n provider: true,\n idToken: true,\n }),\n },\n async (ctx) => {\n const { headers, response } = await linkSocialAccount({\n body: { ...ctx.body, provider: 'link' },\n context: ctx.context,\n headers: ctx.headers,\n ...(ctx.request ? { request: ctx.request } : {}),\n returnHeaders: true,\n });\n\n // Preserve OAuth state cookies and response headers from linkSocialAccount.\n for (const cookie of headers.getSetCookie()) {\n ctx.responseHeaders.append('set-cookie', cookie);\n }\n headers.forEach((value, key) => {\n if (key.toLowerCase() !== 'set-cookie') {\n ctx.responseHeaders.set(key, value);\n }\n });\n\n return ctx.json(response);\n },\n );\n\nexport const disconnectLink = (options: LinkOptions) =>\n createAuthEndpoint(\n '/link/disconnect',\n {\n method: 'POST',\n requireHeaders: true,\n body: z.strictObject({ accountId: z.string().min(1) }),\n use: [sensitiveSessionMiddleware, freshSessionMiddleware],\n },\n async (ctx) => {\n const accounts = await ctx.context.internalAdapter.findAccounts(\n ctx.context.session.user.id,\n );\n const account = accounts.find(\n (candidate) =>\n candidate.id === ctx.body.accountId &&\n candidate.providerId === 'link',\n );\n if (!account) {\n throw APIError.from('BAD_REQUEST', BASE_ERROR_CODES.ACCOUNT_NOT_FOUND);\n }\n if (\n accounts.length === 1 &&\n !ctx.context.options.account?.accountLinking?.allowUnlinkingAll\n ) {\n throw APIError.from(\n 'BAD_REQUEST',\n BASE_ERROR_CODES.FAILED_TO_UNLINK_LAST_ACCOUNT,\n );\n }\n if (!account.refreshToken) {\n throw APIError.from(\n 'BAD_REQUEST',\n LINK_ERROR_CODES.LINK_REFRESH_TOKEN_NOT_FOUND,\n );\n }\n\n let response: Response;\n try {\n const token = await decryptOAuthToken(\n account.refreshToken,\n ctx.context,\n );\n response = await fetch('https://login.link.com/auth/revoke', {\n method: 'POST',\n redirect: 'error',\n signal: AbortSignal.timeout(10_000),\n headers: {\n Authorization: `Bearer ${options.publishableKey}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n client_id: options.clientId,\n client_secret: options.clientSecret,\n token,\n token_type_hint: 'refresh_token',\n }),\n });\n } catch {\n throw APIError.from(\n 'BAD_GATEWAY',\n LINK_ERROR_CODES.LINK_REVOCATION_FAILED,\n );\n }\n if (!response.ok) {\n throw APIError.from(\n 'BAD_GATEWAY',\n LINK_ERROR_CODES.LINK_REVOCATION_FAILED,\n );\n }\n\n await ctx.context.internalAdapter.deleteAccount(account.id);\n return ctx.json({ status: true });\n },\n );\n"],"mappings":"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","names":["z","z"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/routes.ts"],"sourcesContent":["import type { UserInfo } from '@stripe/link-sdk';\nimport type { BetterAuthPlugin } from 'better-auth';\nimport { genericOAuth } from 'better-auth/plugins/generic-oauth';\nimport { z } from 'zod';\nimport { LINK_ERROR_CODES } from './error-codes';\nimport { connectLink, disconnectLink } from './routes';\n\ndeclare module '@better-auth/core' {\n interface BetterAuthPluginRegistry<AuthOptions, Options> {\n link: {\n creator: typeof link;\n };\n }\n}\n\nconst linkProfileSchema = z.object({\n id: z.string().min(1),\n}) satisfies z.ZodType<Pick<UserInfo, 'id'>>;\n\nexport interface LinkOptions {\n clientId: string;\n clientSecret: string;\n publishableKey: string;\n scopes?: string[];\n /** Rich authorization requests, such as `{ type: 'source', actions }`. */\n authorizationDetails?: ReadonlyArray<Record<string, unknown>>;\n redirectURI?: string;\n}\n\nexport function link(options: LinkOptions) {\n for (const field of ['clientId', 'clientSecret', 'publishableKey'] as const) {\n if (!options[field]?.trim()) throw new Error(`Link ${field} is required.`);\n }\n\n const oauth = genericOAuth({\n config: [\n {\n providerId: 'link',\n name: 'Link',\n clientId: options.clientId,\n clientSecret: options.clientSecret,\n redirectURI: options.redirectURI,\n authorizationUrl: 'https://login.link.com/auth',\n tokenUrl: 'https://login.link.com/auth/token',\n userInfoUrl: 'https://api.link.com/userinfo',\n authorizationUrlParams: {\n ...(options.authorizationDetails?.length && {\n authorization_details: JSON.stringify(options.authorizationDetails),\n }),\n key: options.publishableKey,\n },\n scopes: options.scopes ?? ['payment_methods.agentic', 'userinfo:read'],\n pkce: true,\n accessTokenExpiresIn: 3600,\n tokenEndpointAuth: {\n method: 'custom',\n customizeRequest({ body, headers }) {\n body.set('client_id', options.clientId);\n body.set('client_secret', options.clientSecret);\n headers.authorization = `Bearer ${options.publishableKey}`;\n },\n },\n accountSubject: ({ profile }) => linkProfileSchema.parse(profile).id,\n mapProfileToUser(profile) {\n return {\n name:\n profile.name ||\n [profile.first_name, profile.last_name]\n .filter((part) => typeof part === 'string')\n .join(' ') ||\n 'Link',\n };\n },\n },\n ],\n });\n\n return {\n ...oauth,\n id: 'link',\n endpoints: {\n connectLink: connectLink(),\n disconnectLink: disconnectLink(options),\n },\n $ERROR_CODES: LINK_ERROR_CODES,\n } satisfies BetterAuthPlugin;\n}\n\nexport { LINK_ERROR_CODES } from './error-codes';\n","import { BASE_ERROR_CODES } from 'better-auth';\nimport {\n APIError,\n createAuthEndpoint,\n freshSessionMiddleware,\n linkSocialAccount,\n sensitiveSessionMiddleware,\n} from 'better-auth/api';\nimport { decryptOAuthToken } from 'better-auth/oauth2';\nimport { z } from 'zod';\nimport { LINK_ERROR_CODES } from './error-codes';\nimport type { LinkOptions } from './index';\n\nexport const connectLink = () =>\n createAuthEndpoint(\n '/link/connect',\n {\n method: 'POST',\n requireHeaders: true,\n body: linkSocialAccount.options.body.omit({\n provider: true,\n idToken: true,\n }),\n },\n async (ctx) => {\n const { headers, response } = await linkSocialAccount({\n body: { ...ctx.body, provider: 'link' },\n context: ctx.context,\n headers: ctx.headers,\n ...(ctx.request ? { request: ctx.request } : {}),\n returnHeaders: true,\n });\n\n // Preserve OAuth state cookies and response headers from linkSocialAccount.\n for (const cookie of headers.getSetCookie()) {\n ctx.responseHeaders.append('set-cookie', cookie);\n }\n headers.forEach((value, key) => {\n if (key.toLowerCase() !== 'set-cookie') {\n ctx.responseHeaders.set(key, value);\n }\n });\n\n return ctx.json(response);\n },\n );\n\nexport const disconnectLink = (options: LinkOptions) =>\n createAuthEndpoint(\n '/link/disconnect',\n {\n method: 'POST',\n requireHeaders: true,\n body: z.strictObject({ accountId: z.string().min(1) }),\n use: [sensitiveSessionMiddleware, freshSessionMiddleware],\n },\n async (ctx) => {\n const accounts = await ctx.context.internalAdapter.findAccounts(\n ctx.context.session.user.id,\n );\n const account = accounts.find(\n (candidate) =>\n candidate.id === ctx.body.accountId &&\n candidate.providerId === 'link',\n );\n if (!account) {\n throw APIError.from('BAD_REQUEST', BASE_ERROR_CODES.ACCOUNT_NOT_FOUND);\n }\n if (\n accounts.length === 1 &&\n !ctx.context.options.account?.accountLinking?.allowUnlinkingAll\n ) {\n throw APIError.from(\n 'BAD_REQUEST',\n BASE_ERROR_CODES.FAILED_TO_UNLINK_LAST_ACCOUNT,\n );\n }\n if (!account.refreshToken) {\n throw APIError.from(\n 'BAD_REQUEST',\n LINK_ERROR_CODES.LINK_REFRESH_TOKEN_NOT_FOUND,\n );\n }\n\n let response: Response;\n try {\n const token = await decryptOAuthToken(\n account.refreshToken,\n ctx.context,\n );\n response = await fetch('https://login.link.com/auth/revoke', {\n method: 'POST',\n redirect: 'error',\n signal: AbortSignal.timeout(10_000),\n headers: {\n Authorization: `Bearer ${options.publishableKey}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n client_id: options.clientId,\n client_secret: options.clientSecret,\n token,\n token_type_hint: 'refresh_token',\n }),\n });\n } catch {\n throw APIError.from(\n 'BAD_GATEWAY',\n LINK_ERROR_CODES.LINK_REVOCATION_FAILED,\n );\n }\n if (!response.ok) {\n throw APIError.from(\n 'BAD_GATEWAY',\n LINK_ERROR_CODES.LINK_REVOCATION_FAILED,\n );\n }\n\n await ctx.context.internalAdapter.deleteAccount(account.id);\n return ctx.json({ status: true });\n },\n );\n"],"mappings":"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","names":["z","z"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stripe/link-integrations-better-auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Sign in with Link and connect Link wallets using Better Auth",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"tsup": "^8.5.1",
|
|
50
50
|
"typescript": "^7.0.2",
|
|
51
51
|
"vitest": "^5.0.0",
|
|
52
|
-
"@stripe/link-sdk": "0.
|
|
52
|
+
"@stripe/link-sdk": "0.10.0",
|
|
53
53
|
"@stripe/link-typescript-config": "0.0.0"
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|