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.
- package/README.md +348 -0
- package/dist/client.d.ts +42 -0
- package/dist/client.js +52 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +534 -0
- package/dist/schema.d.ts +155 -0
- package/dist/server.d.ts +7 -0
- package/dist/types.d.ts +211 -0
- package/dist/utils.d.ts +88 -0
- package/package.json +58 -0
package/dist/types.d.ts
ADDED
|
@@ -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
|
+
}
|
package/dist/utils.d.ts
ADDED
|
@@ -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
|
+
}
|