better-auth
Version:
The most comprehensive authentication framework for TypeScript.
1 lines • 5.66 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/device-authorization/index.ts"],"sourcesContent":["import type { BetterAuthPlugin } from \"@better-auth/core\";\nimport * as z from \"zod\";\nimport { mergeSchema } from \"../../db\";\nimport type { InferOptionSchema } from \"../../types/plugins\";\nimport type { TimeString } from \"../../utils/time\";\nimport { ms } from \"../../utils/time\";\nimport { DEVICE_AUTHORIZATION_ERROR_CODES } from \"./error-codes\";\nimport {\n\tdeviceApprove,\n\tdeviceCode,\n\tdeviceDeny,\n\tdeviceToken,\n\tdeviceVerify,\n} from \"./routes\";\nimport { schema } from \"./schema\";\n\nconst timeStringSchema = z.custom<TimeString>(\n\t(val) => {\n\t\tif (typeof val !== \"string\") return false;\n\t\ttry {\n\t\t\tms(val as TimeString);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t},\n\t{\n\t\tmessage:\n\t\t\t\"Invalid time string format. Use formats like '30m', '5s', '1h', etc.\",\n\t},\n);\n\nexport const deviceAuthorizationOptionsSchema = z.object({\n\texpiresIn: timeStringSchema\n\t\t.default(\"30m\")\n\t\t.describe(\n\t\t\t\"Time in seconds until the device code expires. Use formats like '30m', '5s', '1h', etc.\",\n\t\t),\n\tinterval: timeStringSchema\n\t\t.default(\"5s\")\n\t\t.describe(\n\t\t\t\"Time in seconds between polling attempts. Use formats like '30m', '5s', '1h', etc.\",\n\t\t),\n\tdeviceCodeLength: z\n\t\t.number()\n\t\t.int()\n\t\t.positive()\n\t\t.default(40)\n\t\t.describe(\n\t\t\t\"Length of the device code to be generated. Default is 40 characters.\",\n\t\t),\n\tuserCodeLength: z\n\t\t.number()\n\t\t.int()\n\t\t.positive()\n\t\t.default(8)\n\t\t.describe(\n\t\t\t\"Length of the user code to be generated. Default is 8 characters.\",\n\t\t),\n\tgenerateDeviceCode: z\n\t\t.custom<() => string | Promise<string>>(\n\t\t\t(val) => typeof val === \"function\",\n\t\t\t{\n\t\t\t\tmessage:\n\t\t\t\t\t\"generateDeviceCode must be a function that returns a string or a promise that resolves to a string.\",\n\t\t\t},\n\t\t)\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"Function to generate a device code. If not provided, a default random string generator will be used.\",\n\t\t),\n\tgenerateUserCode: z\n\t\t.custom<() => string | Promise<string>>(\n\t\t\t(val) => typeof val === \"function\",\n\t\t\t{\n\t\t\t\tmessage:\n\t\t\t\t\t\"generateUserCode must be a function that returns a string or a promise that resolves to a string.\",\n\t\t\t},\n\t\t)\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"Function to generate a user code. If not provided, a default random string generator will be used.\",\n\t\t),\n\tvalidateClient: z\n\t\t.custom<(clientId: string) => boolean | Promise<boolean>>(\n\t\t\t(val) => typeof val === \"function\",\n\t\t\t{\n\t\t\t\tmessage:\n\t\t\t\t\t\"validateClient must be a function that returns a boolean or a promise that resolves to a boolean.\",\n\t\t\t},\n\t\t)\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"Function to validate the client ID. If not provided, no validation will be performed.\",\n\t\t),\n\tonDeviceAuthRequest: z\n\t\t.custom<\n\t\t\t(clientId: string, scope: string | undefined) => void | Promise<void>\n\t\t>((val) => typeof val === \"function\", {\n\t\t\tmessage:\n\t\t\t\t\"onDeviceAuthRequest must be a function that returns void or a promise that resolves to void.\",\n\t\t})\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"Function to handle device authorization requests. If not provided, no additional actions will be taken.\",\n\t\t),\n\tverificationUri: z\n\t\t.string()\n\t\t.optional()\n\t\t.describe(\n\t\t\t\"The URI where users verify their device code. Can be an absolute URL (https://example.com/device) or relative path (/custom-path). This will be returned as verification_uri in the device code response. If not provided, defaults to /device.\",\n\t\t),\n\tschema: z.custom<InferOptionSchema<typeof schema>>(() => true),\n});\n\nexport type DeviceAuthorizationOptions = z.infer<\n\ttypeof deviceAuthorizationOptionsSchema\n>;\n\nexport const deviceAuthorization = (\n\toptions: Partial<DeviceAuthorizationOptions> = {},\n) => {\n\tconst opts = deviceAuthorizationOptionsSchema.parse(options);\n\n\treturn {\n\t\tid: \"device-authorization\",\n\t\tschema: mergeSchema(schema, options?.schema),\n\t\tendpoints: {\n\t\t\tdeviceCode: deviceCode(opts),\n\t\t\tdeviceToken: deviceToken(opts),\n\t\t\tdeviceVerify,\n\t\t\tdeviceApprove,\n\t\t\tdeviceDeny,\n\t\t},\n\t\t$ERROR_CODES: DEVICE_AUTHORIZATION_ERROR_CODES,\n\t\toptions,\n\t} satisfies BetterAuthPlugin;\n};\n\nexport type * from \"../../utils/time\";\n"],"mappings":";;;;;;;;;AAgBA,MAAM,mBAAmB,EAAE,QACzB,QAAQ;AACR,KAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,KAAI;AACH,KAAG,IAAkB;AACrB,SAAO;SACA;AACP,SAAO;;GAGT,EACC,SACC,wEACD,CACD;AAED,MAAa,mCAAmC,EAAE,OAAO;CACxD,WAAW,iBACT,QAAQ,MAAM,CACd,SACA,0FACA;CACF,UAAU,iBACR,QAAQ,KAAK,CACb,SACA,qFACA;CACF,kBAAkB,EAChB,QAAQ,CACR,KAAK,CACL,UAAU,CACV,QAAQ,GAAG,CACX,SACA,uEACA;CACF,gBAAgB,EACd,QAAQ,CACR,KAAK,CACL,UAAU,CACV,QAAQ,EAAE,CACV,SACA,oEACA;CACF,oBAAoB,EAClB,QACC,QAAQ,OAAO,QAAQ,YACxB,EACC,SACC,uGACD,CACD,CACA,UAAU,CACV,SACA,uGACA;CACF,kBAAkB,EAChB,QACC,QAAQ,OAAO,QAAQ,YACxB,EACC,SACC,qGACD,CACD,CACA,UAAU,CACV,SACA,qGACA;CACF,gBAAgB,EACd,QACC,QAAQ,OAAO,QAAQ,YACxB,EACC,SACC,qGACD,CACD,CACA,UAAU,CACV,SACA,wFACA;CACF,qBAAqB,EACnB,QAEE,QAAQ,OAAO,QAAQ,YAAY,EACrC,SACC,gGACD,CAAC,CACD,UAAU,CACV,SACA,0GACA;CACF,iBAAiB,EACf,QAAQ,CACR,UAAU,CACV,SACA,kPACA;CACF,QAAQ,EAAE,aAA+C,KAAK;CAC9D,CAAC;AAMF,MAAa,uBACZ,UAA+C,EAAE,KAC7C;CACJ,MAAM,OAAO,iCAAiC,MAAM,QAAQ;AAE5D,QAAO;EACN,IAAI;EACJ,QAAQ,YAAY,QAAQ,SAAS,OAAO;EAC5C,WAAW;GACV,YAAY,WAAW,KAAK;GAC5B,aAAa,YAAY,KAAK;GAC9B;GACA;GACA;GACA;EACD,cAAc;EACd;EACA"}