atproto-better-auth 0.1.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.
@@ -0,0 +1,211 @@
1
+ import type { User } from "better-auth";
2
+ import type { NodeOAuthClientOptions } from "@atproto/oauth-client-node";
3
+ /**
4
+ * ES256 JSON Web Key with private key component
5
+ */
6
+ export interface ES256PrivateJwk {
7
+ kty: "EC";
8
+ crv: "P-256";
9
+ x: string;
10
+ y: string;
11
+ d: string;
12
+ alg?: "ES256";
13
+ kid?: string;
14
+ }
15
+ /**
16
+ * ES256 JSON Web Key (public only, for JWKS endpoint)
17
+ */
18
+ export interface ES256PublicJwk {
19
+ kty: "EC";
20
+ crv: "P-256";
21
+ x: string;
22
+ y: string;
23
+ alg?: "ES256";
24
+ kid?: string;
25
+ }
26
+ /**
27
+ * OAuth client metadata that must be served at the clientId URL
28
+ */
29
+ export interface AtprotoClientMetadata {
30
+ client_id: string;
31
+ client_name: string;
32
+ client_uri?: string;
33
+ logo_uri?: string;
34
+ tos_uri?: string;
35
+ policy_uri?: string;
36
+ redirect_uris: string[];
37
+ grant_types: ["authorization_code", "refresh_token"];
38
+ response_types: ["code"];
39
+ scope: string;
40
+ dpop_bound_access_tokens: true;
41
+ application_type: "web" | "native";
42
+ token_endpoint_auth_method: "private_key_jwt" | "none";
43
+ token_endpoint_auth_signing_alg?: "ES256";
44
+ jwks_uri?: string;
45
+ }
46
+ /**
47
+ * ATProto user profile information
48
+ */
49
+ export interface AtprotoProfile {
50
+ did: string;
51
+ handle: string;
52
+ displayName?: string;
53
+ avatar?: string;
54
+ description?: string;
55
+ banner?: string;
56
+ }
57
+ /**
58
+ * Client metadata input with required URLs.
59
+ * Used for utility functions like createClientMetadata() where URLs cannot be auto-derived.
60
+ */
61
+ export interface AtprotoClientMetadataInput {
62
+ /**
63
+ * Human-readable name of your application
64
+ */
65
+ clientName: string;
66
+ /**
67
+ * The URL where your client-metadata.json is hosted.
68
+ * This becomes your OAuth client_id.
69
+ */
70
+ clientId: string;
71
+ /**
72
+ * Homepage URL for your application.
73
+ */
74
+ clientUri?: string;
75
+ /**
76
+ * URL to your application's logo
77
+ */
78
+ logoUri?: string;
79
+ /**
80
+ * URL to your terms of service
81
+ */
82
+ tosUri?: string;
83
+ /**
84
+ * URL to your privacy policy
85
+ */
86
+ policyUri?: string;
87
+ /**
88
+ * OAuth redirect URIs. Should include your callback endpoint.
89
+ */
90
+ redirectUris: string[];
91
+ /**
92
+ * OAuth scopes to request. Defaults to "atproto transition:generic"
93
+ */
94
+ scope?: string;
95
+ /**
96
+ * URL where your JWKS (public keys) are hosted.
97
+ * Required for confidential (web service) clients.
98
+ */
99
+ jwksUri?: string;
100
+ }
101
+ /**
102
+ * Plugin configuration options
103
+ */
104
+ export interface AtprotoAuthOptions {
105
+ /**
106
+ * Client metadata configuration.
107
+ * URLs are automatically derived from Better Auth's baseURL unless explicitly set.
108
+ */
109
+ clientMetadata: {
110
+ /**
111
+ * Human-readable name of your application
112
+ */
113
+ clientName: string;
114
+ /**
115
+ * The URL where your client-metadata.json is hosted.
116
+ * This becomes your OAuth client_id.
117
+ * Defaults to `{baseURL}/client-metadata.json`
118
+ */
119
+ clientId?: string;
120
+ /**
121
+ * Homepage URL for your application.
122
+ * Defaults to Better Auth's baseURL (with /api/auth stripped).
123
+ */
124
+ clientUri?: string;
125
+ /**
126
+ * URL to your application's logo
127
+ */
128
+ logoUri?: string;
129
+ /**
130
+ * URL to your terms of service
131
+ */
132
+ tosUri?: string;
133
+ /**
134
+ * URL to your privacy policy
135
+ */
136
+ policyUri?: string;
137
+ /**
138
+ * OAuth redirect URIs. Should include your callback endpoint.
139
+ * Defaults to `[{baseURL}/callback/atproto]`
140
+ */
141
+ redirectUris?: string[];
142
+ /**
143
+ * OAuth scopes to request. Defaults to "atproto transition:generic"
144
+ */
145
+ scope?: string;
146
+ /**
147
+ * URL where your JWKS (public keys) are hosted.
148
+ * Required for confidential (web service) clients.
149
+ * Defaults to `{appBaseURL}/jwks.json`
150
+ */
151
+ jwksUri?: string;
152
+ };
153
+ /**
154
+ * ES256 private key in JWK format.
155
+ * Must include the "d" (private key) component.
156
+ * Generate at https://jwkset.com/generate with:
157
+ * - Key type: ECDSA
158
+ * - Key algorithm: ES256
159
+ * - Key use: Signature
160
+ */
161
+ privateKey: ES256PrivateJwk;
162
+ /**
163
+ * Map ATProto profile to user fields during account creation/linking
164
+ */
165
+ mapProfileToUser?: (profile: AtprotoProfile) => Partial<User>;
166
+ /**
167
+ * Custom NodeOAuthClient options for advanced configuration.
168
+ * Merged with generated options from clientMetadata.
169
+ */
170
+ oauthClientOptions?: Partial<NodeOAuthClientOptions>;
171
+ }
172
+ /**
173
+ * Stored OAuth state during authorization flow
174
+ */
175
+ export interface AtprotoStateRecord {
176
+ key: string;
177
+ state: string;
178
+ expiresAt: Date;
179
+ }
180
+ /**
181
+ * Stored ATProto OAuth session
182
+ */
183
+ export interface AtprotoSessionRecord {
184
+ did: string;
185
+ session: string;
186
+ userId: string;
187
+ updatedAt: Date;
188
+ }
189
+ /**
190
+ * ATProto session info returned to client
191
+ */
192
+ export interface AtprotoSessionInfo {
193
+ did: string;
194
+ handle: string;
195
+ displayName?: string;
196
+ avatar?: string;
197
+ active: boolean;
198
+ }
199
+ /**
200
+ * Sign-in request parameters
201
+ */
202
+ export interface AtprotoSignInParams {
203
+ /**
204
+ * The user's ATProto handle (e.g., "user.bsky.social")
205
+ */
206
+ handle: string;
207
+ /**
208
+ * URL to redirect to after successful authentication
209
+ */
210
+ callbackURL?: string;
211
+ }
@@ -0,0 +1,88 @@
1
+ import type { ES256PrivateJwk, ES256PublicJwk, AtprotoClientMetadata, AtprotoClientMetadataInput } from "./types.js";
2
+ /**
3
+ * Extracts the public key from an ES256 private JWK.
4
+ * Use this to create your JWKS endpoint content.
5
+ *
6
+ * @param privateKey - The ES256 private key in JWK format
7
+ * @returns The public key in JWK format (without the "d" component)
8
+ */
9
+ export declare function getPublicJwk(privateKey: ES256PrivateJwk): ES256PublicJwk;
10
+ /**
11
+ * Creates a JWKS (JSON Web Key Set) object from a private key.
12
+ * This is what should be served at your /jwks.json endpoint.
13
+ *
14
+ * @param privateKey - The ES256 private key in JWK format
15
+ * @returns A JWKS object with the public key
16
+ */
17
+ export declare function createJwks(privateKey: ES256PrivateJwk): {
18
+ keys: ES256PublicJwk[];
19
+ };
20
+ /**
21
+ * Options for createClientMetadata utility function.
22
+ */
23
+ export interface CreateClientMetadataOptions {
24
+ clientMetadata: AtprotoClientMetadataInput;
25
+ privateKey: ES256PrivateJwk;
26
+ }
27
+ /**
28
+ * Creates the client metadata object for the /client-metadata.json endpoint.
29
+ *
30
+ * @param options - The client metadata and private key
31
+ * @returns The client metadata object to serve at your clientId URL
32
+ */
33
+ export declare function createClientMetadata(options: CreateClientMetadataOptions): AtprotoClientMetadata;
34
+ /**
35
+ * Generates a new ES256 key pair for ATProto OAuth.
36
+ *
37
+ * Note: This uses the Web Crypto API which is available in Node.js 15+
38
+ * and modern browsers. For older environments, use a library like jose.
39
+ *
40
+ * @returns A promise that resolves to an ES256 private key in JWK format
41
+ */
42
+ export declare function generateES256Key(): Promise<ES256PrivateJwk>;
43
+ /**
44
+ * Validates that a JWK has all required fields for an ES256 private key.
45
+ *
46
+ * @param jwk - The JWK to validate
47
+ * @returns True if the JWK is a valid ES256 private key
48
+ */
49
+ export declare function isValidES256PrivateKey(jwk: unknown): jwk is ES256PrivateJwk;
50
+ /**
51
+ * Helper to create a Next.js API route handler for /client-metadata.json
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * // app/client-metadata.json/route.ts
56
+ * import { createClientMetadataHandler } from "atproto-better-auth/utils";
57
+ *
58
+ * export const GET = createClientMetadataHandler({
59
+ * clientMetadata: {
60
+ * clientId: "https://example.com/client-metadata.json",
61
+ * clientName: "My App",
62
+ * redirectUris: ["https://example.com/api/auth/callback/atproto"],
63
+ * jwksUri: "https://example.com/jwks.json",
64
+ * },
65
+ * privateKey,
66
+ * });
67
+ * ```
68
+ */
69
+ export declare function createClientMetadataHandler(options: CreateClientMetadataOptions): () => Response;
70
+ /**
71
+ * Helper to create a Next.js API route handler for /jwks.json
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * // app/jwks.json/route.ts
76
+ * import { createJwksHandler } from "atproto-better-auth/utils";
77
+ * import { authOptions } from "@/lib/auth";
78
+ *
79
+ * export const GET = createJwksHandler(authOptions.privateKey);
80
+ * ```
81
+ */
82
+ export declare function createJwksHandler(privateKey: ES256PrivateJwk): () => Response;
83
+ /**
84
+ * Default scopes for ATProto OAuth.
85
+ * - atproto: Required for all ATProto OAuth requests
86
+ * - transition:generic: Transitional scope for general API access
87
+ */
88
+ export declare const DEFAULT_ATPROTO_SCOPES = "atproto transition:generic";
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "atproto-better-auth",
3
+ "version": "0.1.0",
4
+ "description": "A better-auth plugin for ATProto/Bluesky OAuth authentication",
5
+ "author": "AugusDogus",
6
+ "private": false,
7
+ "license": "MIT",
8
+ "type": "module",
9
+ "main": "./dist/index.js",
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ },
17
+ "./client": {
18
+ "import": "./dist/client.js",
19
+ "types": "./dist/client.d.ts"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "keywords": [
26
+ "better-auth",
27
+ "atproto",
28
+ "bluesky",
29
+ "oauth",
30
+ "authentication"
31
+ ],
32
+ "homepage": "https://github.com/AugusDogus/atproto-better-auth",
33
+ "repository": "github:AugusDogus/atproto-better-auth",
34
+ "bugs": "https://github.com/AugusDogus/atproto-better-auth/issues",
35
+ "scripts": {
36
+ "clean": "rm -rf dist",
37
+ "build": "bun run clean && bun build:types && bun build:js",
38
+ "build:js": "bun build ./src/index.ts ./src/client.ts --outdir ./dist --target node --format esm --splitting --packages external",
39
+ "build:types": "tsc",
40
+ "test": "bun test",
41
+ "prepublishOnly": "cp ../../README.md .",
42
+ "release": "bumpp --commit --push --tag"
43
+ },
44
+ "peerDependencies": {
45
+ "better-auth": ">=1.0.0"
46
+ },
47
+ "dependencies": {
48
+ "@atproto/api": "^0.18.17",
49
+ "@atproto/oauth-client-node": "^0.3.15",
50
+ "zod": "^4.3.6"
51
+ },
52
+ "devDependencies": {
53
+ "@types/bun": "^1.3.6",
54
+ "better-auth": "^1.4.17",
55
+ "bumpp": "^10.4.0",
56
+ "typescript": "^5.9.3"
57
+ }
58
+ }