better-near-auth 0.3.3 → 0.5.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 +134 -93
- package/dist/client.d.ts +70 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +362 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +387 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +566 -0
- package/dist/index.js.map +1 -0
- package/dist/profile.d.ts +6 -0
- package/dist/profile.d.ts.map +1 -0
- package/dist/profile.js +46 -0
- package/dist/profile.js.map +1 -0
- package/dist/schema.d.ts +35 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +35 -0
- package/dist/schema.js.map +1 -0
- package/dist/types.d.ts +117 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +55 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +7 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +11 -0
- package/dist/utils.js.map +1 -0
- package/package.json +34 -36
- package/src/client.ts +0 -461
- package/src/index.ts +0 -661
- package/src/near.test.ts +0 -331
- package/src/profile.ts +0 -63
- package/src/schema.ts +0 -36
- package/src/types.ts +0 -90
- package/src/utils.ts +0 -13
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
|
-
This [Better Auth](https://better-auth.com) plugin enables secure authentication via NEAR wallets and keypairs by following the [NEP-413 standard](https://github.com/near/NEPs/blob/master/neps/nep-0413.md). It leverages [near-sign-verify](https://github.com/elliotBraem/near-sign-verify), [near-kit](https://kit.near.tools/), and [
|
|
16
|
+
This [Better Auth](https://better-auth.com) plugin enables secure authentication via NEAR wallets and keypairs by following the [NEP-413 standard](https://github.com/near/NEPs/blob/master/neps/nep-0413.md). It leverages [near-sign-verify](https://github.com/elliotBraem/near-sign-verify), [near-kit](https://kit.near.tools/), and [NEAR Connect](https://github.com/azbang/near-connect) to provide a complete drop-in solution with session management, secure defaults, and automatic profile integration.
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
@@ -57,7 +57,7 @@ npm install better-near-auth
|
|
|
57
57
|
export const authClient = createAuthClient({
|
|
58
58
|
plugins: [
|
|
59
59
|
siwnClient({
|
|
60
|
-
|
|
60
|
+
recipient: "myapp.com",
|
|
61
61
|
networkId: "mainnet", // optional, default is "mainnet"
|
|
62
62
|
})
|
|
63
63
|
],
|
|
@@ -66,42 +66,9 @@ npm install better-near-auth
|
|
|
66
66
|
|
|
67
67
|
## Usage
|
|
68
68
|
|
|
69
|
-
###
|
|
70
|
-
|
|
71
|
-
The plugin uses a secure two-step authentication process:
|
|
72
|
-
|
|
73
|
-
1. **Step 1**: Connect wallet and cache nonce
|
|
74
|
-
2. **Step 2**: Sign message and authenticate
|
|
75
|
-
|
|
76
|
-
```ts title="two-step-auth.ts"
|
|
77
|
-
// Step 1: Connect wallet and get nonce
|
|
78
|
-
await authClient.requestSignIn.near(
|
|
79
|
-
{ recipient: "myapp.com" },
|
|
80
|
-
{
|
|
81
|
-
onSuccess: () => {
|
|
82
|
-
console.log("Wallet connected, nonce cached!");
|
|
83
|
-
},
|
|
84
|
-
onError: (error) => {
|
|
85
|
-
console.error("Wallet connection failed:", error.message);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
// Step 2: Sign message and authenticate
|
|
91
|
-
await authClient.signIn.near(
|
|
92
|
-
{ recipient: "myapp.com" },
|
|
93
|
-
{
|
|
94
|
-
onSuccess: () => {
|
|
95
|
-
console.log("Successfully signed in!");
|
|
96
|
-
},
|
|
97
|
-
onError: (error) => {
|
|
98
|
-
console.error("Sign in failed:", error.message);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
);
|
|
102
|
-
```
|
|
69
|
+
### Single-Step Authentication Flow
|
|
103
70
|
|
|
104
|
-
|
|
71
|
+
The plugin uses a single-step authentication flow that automatically handles both wallet connection and message signing:
|
|
105
72
|
|
|
106
73
|
```tsx title="LoginButton.tsx"
|
|
107
74
|
import { authClient } from "./auth-client";
|
|
@@ -109,56 +76,71 @@ import { useState } from "react";
|
|
|
109
76
|
|
|
110
77
|
export function LoginButton() {
|
|
111
78
|
const { data: session } = authClient.useSession();
|
|
112
|
-
const [isConnectingWallet, setIsConnectingWallet] = useState(false);
|
|
113
79
|
const [isSigningIn, setIsSigningIn] = useState(false);
|
|
114
|
-
|
|
115
|
-
// Get account ID from near-kit client
|
|
116
|
-
const accountId = authClient.near.getAccountId();
|
|
117
80
|
|
|
118
81
|
if (session) {
|
|
119
82
|
return (
|
|
120
83
|
<div>
|
|
121
84
|
<p>Welcome, {session.user.name}!</p>
|
|
122
|
-
<button onClick={() => authClient.
|
|
85
|
+
<button onClick={() => authClient.near.disconnect()}>Sign out</button>
|
|
123
86
|
</div>
|
|
124
87
|
);
|
|
125
88
|
}
|
|
126
89
|
|
|
127
|
-
const handleWalletConnect = async () => {
|
|
128
|
-
setIsConnectingWallet(true);
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
await authClient.requestSignIn.near(
|
|
132
|
-
{ recipient: "myapp.com" },
|
|
133
|
-
{
|
|
134
|
-
onSuccess: () => {
|
|
135
|
-
setIsConnectingWallet(false);
|
|
136
|
-
console.log("Wallet connected!");
|
|
137
|
-
},
|
|
138
|
-
onError: (error) => {
|
|
139
|
-
setIsConnectingWallet(false);
|
|
140
|
-
console.error("Wallet connection failed:", error.message);
|
|
141
|
-
},
|
|
142
|
-
}
|
|
143
|
-
);
|
|
144
|
-
} catch (error) {
|
|
145
|
-
setIsConnectingWallet(false);
|
|
146
|
-
console.error("Authentication error:", error);
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
|
|
150
90
|
const handleSignIn = async () => {
|
|
151
91
|
setIsSigningIn(true);
|
|
152
92
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
93
|
+
await authClient.signIn.near({
|
|
94
|
+
onSuccess: () => {
|
|
95
|
+
setIsSigningIn(false);
|
|
96
|
+
console.log("Successfully signed in!");
|
|
97
|
+
},
|
|
98
|
+
onError: (error) => {
|
|
99
|
+
setIsSigningIn(false);
|
|
100
|
+
console.error("Sign in failed:", error.message);
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<button onClick={handleSignIn} disabled={isSigningIn}>
|
|
107
|
+
{isSigningIn ? "Signing in..." : "Sign in with NEAR"}
|
|
108
|
+
</button>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### How It Works
|
|
114
|
+
|
|
115
|
+
The `signIn.near()` method automatically:
|
|
116
|
+
|
|
117
|
+
1. **Checks wallet capabilities** - Detects if the wallet supports `signInAndSignMessage`
|
|
118
|
+
2. **Single-step flow** (supported wallets): One popup for connection + signing
|
|
119
|
+
3. **Two-step fallback** (unsupported wallets): Automatic fallback to connect then sign
|
|
120
|
+
|
|
121
|
+
**Supported wallets for single-step:**
|
|
122
|
+
- Meteor Wallet
|
|
123
|
+
- Intear Wallet
|
|
124
|
+
- NEAR CLI
|
|
125
|
+
- HOT Wallet
|
|
126
|
+
- MyNearWallet
|
|
127
|
+
- And more...
|
|
128
|
+
|
|
129
|
+
### Manual Two-Step Flow (Optional)
|
|
130
|
+
|
|
131
|
+
If you need explicit control over the connection step:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
// Step 1: Connect wallet (optional, for explicit control)
|
|
135
|
+
await authClient.requestSignIn.near({
|
|
136
|
+
onSuccess: () => console.log("Wallet connected"),
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Step 2: Sign and authenticate
|
|
140
|
+
await authClient.signIn.near({
|
|
141
|
+
onSuccess: () => console.log("Signed in!"),
|
|
142
|
+
});
|
|
143
|
+
```
|
|
162
144
|
setIsSigningIn(false);
|
|
163
145
|
console.error("Sign in failed:", error.message);
|
|
164
146
|
},
|
|
@@ -172,15 +154,9 @@ export function LoginButton() {
|
|
|
172
154
|
|
|
173
155
|
return (
|
|
174
156
|
<div>
|
|
175
|
-
{
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
</button>
|
|
179
|
-
) : (
|
|
180
|
-
<button onClick={handleSignIn} disabled={isSigningIn}>
|
|
181
|
-
{isSigningIn ? "Signing in..." : `Sign in with NEAR (${accountId})`}
|
|
182
|
-
</button>
|
|
183
|
-
)}
|
|
157
|
+
<button onClick={handleSignIn} disabled={isSigningIn}>
|
|
158
|
+
{isSigningIn ? "Signing in..." : "Sign in with NEAR"}
|
|
159
|
+
</button>
|
|
184
160
|
</div>
|
|
185
161
|
);
|
|
186
162
|
}
|
|
@@ -235,7 +211,7 @@ The SIWN plugin accepts the following configuration options:
|
|
|
235
211
|
|
|
236
212
|
The SIWN client plugin accepts the following configuration options:
|
|
237
213
|
|
|
238
|
-
* **
|
|
214
|
+
* **recipient**: The recipient identifier for NEP-413 messages (must match server config)
|
|
239
215
|
* **networkId**: NEAR network to use ("mainnet" or "testnet"). Default is "mainnet"
|
|
240
216
|
|
|
241
217
|
```ts title="auth-client.ts"
|
|
@@ -245,7 +221,7 @@ import { siwnClient } from "better-near-auth/client";
|
|
|
245
221
|
export const authClient = createAuthClient({
|
|
246
222
|
plugins: [
|
|
247
223
|
siwnClient({
|
|
248
|
-
|
|
224
|
+
recipient: "myapp.com",
|
|
249
225
|
networkId: "testnet", // Use testnet
|
|
250
226
|
}),
|
|
251
227
|
],
|
|
@@ -280,14 +256,17 @@ The client plugin provides the following actions:
|
|
|
280
256
|
- `getNearClient()` - Get the near-kit client instance
|
|
281
257
|
- `getAccountId()` - Get the currently connected account ID
|
|
282
258
|
- `disconnect()` - Disconnect wallet and clear cached data
|
|
259
|
+
- `link(callbacks?)` - Link a NEAR account to the current session
|
|
260
|
+
- `unlink(params)` - Unlink a NEAR account from the current session
|
|
261
|
+
- `listAccounts()` - List all linked NEAR accounts
|
|
283
262
|
|
|
284
263
|
#### `authClient.requestSignIn`
|
|
285
264
|
|
|
286
|
-
- `near(
|
|
265
|
+
- `near(callbacks?)` - Connect wallet and cache nonce (for two-step flow)
|
|
287
266
|
|
|
288
267
|
#### `authClient.signIn`
|
|
289
268
|
|
|
290
|
-
- `near(
|
|
269
|
+
- `near(callbacks?)` - Sign message and authenticate (single-step or two-step)
|
|
291
270
|
|
|
292
271
|
### Callback Interface
|
|
293
272
|
|
|
@@ -303,10 +282,10 @@ interface AuthCallbacks {
|
|
|
303
282
|
Common error codes you may encounter:
|
|
304
283
|
|
|
305
284
|
- `SIGNER_NOT_AVAILABLE` - NEAR wallet not available
|
|
306
|
-
- `WALLET_NOT_CONNECTED` - Wallet not connected before signing
|
|
307
|
-
- `
|
|
308
|
-
- `
|
|
309
|
-
- `
|
|
285
|
+
- `WALLET_NOT_CONNECTED` - Wallet not connected before signing (two-step fallback)
|
|
286
|
+
- `ACCOUNT_MISMATCH` - Cached nonce doesn't match current account (two-step fallback)
|
|
287
|
+
- `UNAUTHORIZED_NONCE_REPLAY` - Nonce already used (replay attack detected)
|
|
288
|
+
- `UNAUTHORIZED_INVALID_SIGNATURE` - Invalid signature verification
|
|
310
289
|
|
|
311
290
|
## Advanced Configuration
|
|
312
291
|
|
|
@@ -446,6 +425,67 @@ export const authClient = createAuthClient({
|
|
|
446
425
|
- Testnet accounts must use "testnet", mainnet accounts use "mainnet"
|
|
447
426
|
|
|
448
427
|
|
|
428
|
+
## Examples
|
|
429
|
+
|
|
430
|
+
This repository includes example applications demonstrating how to use better-near-auth:
|
|
431
|
+
|
|
432
|
+
### Browser to Server Example
|
|
433
|
+
|
|
434
|
+
A full-stack example showing NEAR authentication in a browser app with a server backend.
|
|
435
|
+
|
|
436
|
+
- **Location**: `examples/browser-2-server/`
|
|
437
|
+
- **Live Demo**: [better-near-auth.near.page](https://better-near-auth.near.page)
|
|
438
|
+
- **Tech Stack**: Hono, Drizzle ORM, React, TanStack Router
|
|
439
|
+
|
|
440
|
+
**Running locally:**
|
|
441
|
+
```bash
|
|
442
|
+
# From repo root
|
|
443
|
+
pnpm install
|
|
444
|
+
cd examples/browser-2-server
|
|
445
|
+
pnpm dev
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
**Deployment:**
|
|
449
|
+
Each example can be deployed independently to Railway or other platforms. See the example's README for deployment instructions.
|
|
450
|
+
|
|
451
|
+
## Development
|
|
452
|
+
|
|
453
|
+
Interested in contributing? See [CONTRIBUTING.md](./CONTRIBUTING.md) for:
|
|
454
|
+
- Development setup
|
|
455
|
+
- How to add changesets
|
|
456
|
+
- Pull request guidelines
|
|
457
|
+
- Release process
|
|
458
|
+
|
|
459
|
+
**Quick start:**
|
|
460
|
+
```bash
|
|
461
|
+
# Install dependencies
|
|
462
|
+
pnpm install
|
|
463
|
+
|
|
464
|
+
# Build the package
|
|
465
|
+
pnpm build
|
|
466
|
+
|
|
467
|
+
# Run type checking
|
|
468
|
+
pnpm typecheck
|
|
469
|
+
|
|
470
|
+
# Run tests
|
|
471
|
+
pnpm test
|
|
472
|
+
|
|
473
|
+
# Run example locally
|
|
474
|
+
cd examples/browser-2-server && pnpm dev
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**Build output:**
|
|
478
|
+
- `dist/index.js` - Server plugin (ESM)
|
|
479
|
+
- `dist/client.js` - Client plugin (ESM)
|
|
480
|
+
- `dist/*.d.ts` - TypeScript declarations
|
|
481
|
+
|
|
482
|
+
**Deployment workflow:**
|
|
483
|
+
1. Make changes and create changeset
|
|
484
|
+
2. Merge PR → Changesets publishes to npm
|
|
485
|
+
3. Example auto-updates to use published version
|
|
486
|
+
4. Railway auto-deploys
|
|
487
|
+
5. Example reverts to `workspace:*` for next development cycle
|
|
488
|
+
|
|
449
489
|
## Links
|
|
450
490
|
|
|
451
491
|
* [Better Auth Documentation](https://better-auth.com)
|
|
@@ -453,5 +493,6 @@ export const authClient = createAuthClient({
|
|
|
453
493
|
* [NEP-413 Specification](https://github.com/near/NEPs/blob/master/neps/nep-0413.md)
|
|
454
494
|
* [near-sign-verify](https://github.com/elliotBraem/near-sign-verify)
|
|
455
495
|
* [near-kit](https://kit.near.tools/)
|
|
456
|
-
* [
|
|
457
|
-
* [Example Implementation](https://better-near-auth.near.page)
|
|
496
|
+
* [NEAR Connect](https://github.com/azbang/near-connect)
|
|
497
|
+
* [Example Implementation](https://better-near-auth.near.page) - Live demo
|
|
498
|
+
* [Contributing Guide](./CONTRIBUTING.md) - Development and contribution guidelines
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { BetterAuthClientPlugin, BetterFetch, BetterFetchResponse } from "better-auth/client";
|
|
2
|
+
import { atom } from "nanostores";
|
|
3
|
+
import { Near } from "near-kit";
|
|
4
|
+
import type { siwn } from "./index.js";
|
|
5
|
+
import { type AccountId, type NonceRequestT, type NonceResponseT, type ProfileResponseT, type VerifyRequestT, type VerifyResponseT } from "./types.js";
|
|
6
|
+
export interface AuthCallbacks {
|
|
7
|
+
onSuccess?: () => void;
|
|
8
|
+
onError?: (error: Error & {
|
|
9
|
+
status?: number;
|
|
10
|
+
code?: string;
|
|
11
|
+
}) => void;
|
|
12
|
+
}
|
|
13
|
+
export interface SIWNClientConfig {
|
|
14
|
+
recipient: string;
|
|
15
|
+
networkId?: "mainnet" | "testnet";
|
|
16
|
+
}
|
|
17
|
+
export interface CachedNonceData {
|
|
18
|
+
nonce: string;
|
|
19
|
+
accountId: string;
|
|
20
|
+
publicKey?: string | null;
|
|
21
|
+
networkId: string;
|
|
22
|
+
timestamp: number;
|
|
23
|
+
}
|
|
24
|
+
export interface SIWNClientActions {
|
|
25
|
+
near: {
|
|
26
|
+
nonce: (params: NonceRequestT) => Promise<BetterFetchResponse<NonceResponseT>>;
|
|
27
|
+
verify: (params: VerifyRequestT) => Promise<BetterFetchResponse<VerifyResponseT>>;
|
|
28
|
+
getProfile: (accountId?: AccountId) => Promise<BetterFetchResponse<ProfileResponseT>>;
|
|
29
|
+
getNearClient: () => Near;
|
|
30
|
+
getAccountId: () => string | null;
|
|
31
|
+
getState: () => {
|
|
32
|
+
accountId: string | null;
|
|
33
|
+
publicKey: string | null;
|
|
34
|
+
networkId: string;
|
|
35
|
+
} | null;
|
|
36
|
+
disconnect: () => Promise<void>;
|
|
37
|
+
link: (callbacks?: AuthCallbacks) => Promise<void>;
|
|
38
|
+
unlink: (params: {
|
|
39
|
+
accountId: string;
|
|
40
|
+
network?: "mainnet" | "testnet";
|
|
41
|
+
}) => Promise<BetterFetchResponse<{
|
|
42
|
+
success: boolean;
|
|
43
|
+
message: string;
|
|
44
|
+
}>>;
|
|
45
|
+
listAccounts: () => Promise<BetterFetchResponse<{
|
|
46
|
+
accounts: any[];
|
|
47
|
+
}>>;
|
|
48
|
+
};
|
|
49
|
+
requestSignIn: {
|
|
50
|
+
near: (callbacks?: AuthCallbacks) => Promise<void>;
|
|
51
|
+
};
|
|
52
|
+
signIn: {
|
|
53
|
+
near: (callbacks?: AuthCallbacks) => Promise<void>;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export interface SIWNClientPlugin extends BetterAuthClientPlugin {
|
|
57
|
+
id: "siwn";
|
|
58
|
+
$InferServerPlugin: ReturnType<typeof siwn>;
|
|
59
|
+
getAtoms: ($fetch: BetterFetch) => {
|
|
60
|
+
nearState: ReturnType<typeof atom<{
|
|
61
|
+
accountId: string | null;
|
|
62
|
+
publicKey: string | null;
|
|
63
|
+
networkId: string;
|
|
64
|
+
} | null>>;
|
|
65
|
+
cachedNonce: ReturnType<typeof atom<CachedNonceData | null>>;
|
|
66
|
+
};
|
|
67
|
+
getActions: ($fetch: BetterFetch) => SIWNClientActions;
|
|
68
|
+
}
|
|
69
|
+
export declare const siwnClient: (config: SIWNClientConfig) => SIWNClientPlugin;
|
|
70
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|