@stripe/link-integrations-better-auth 0.2.0 → 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 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): {
@@ -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;;;;;;;;;;QA+CnC,WAAW;;;;;;;;;;;;;;;;;QACX,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAInB;AAED,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
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: { key: options.publishableKey },
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.2.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",
@@ -35,12 +35,6 @@
35
35
  "publishConfig": {
36
36
  "access": "public"
37
37
  },
38
- "scripts": {
39
- "build": "tsup && tsc --noEmit false --emitDeclarationOnly",
40
- "prepack": "pnpm run build",
41
- "typecheck": "tsc && tsc -p tsconfig.test.json",
42
- "test": "vitest run"
43
- },
44
38
  "peerDependencies": {
45
39
  "@better-auth/core": "^1.7.5",
46
40
  "better-auth": "^1.7.5"
@@ -50,12 +44,17 @@
50
44
  },
51
45
  "devDependencies": {
52
46
  "@better-auth/core": "1.7.5",
53
- "@stripe/link-sdk": "workspace:*",
54
- "@stripe/link-typescript-config": "workspace:*",
55
47
  "@types/node": "^26.4.1",
56
48
  "better-auth": "1.7.5",
57
49
  "tsup": "^8.5.1",
58
50
  "typescript": "^7.0.2",
59
- "vitest": "^5.0.0"
51
+ "vitest": "^5.0.0",
52
+ "@stripe/link-sdk": "0.10.0",
53
+ "@stripe/link-typescript-config": "0.0.0"
54
+ },
55
+ "scripts": {
56
+ "build": "tsup && tsc --noEmit false --emitDeclarationOnly",
57
+ "typecheck": "tsc && tsc -p tsconfig.test.json",
58
+ "test": "vitest run"
60
59
  }
61
- }
60
+ }