better-near-auth 0.6.0 → 1.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 +34 -74
- package/dist/client.d.ts +11 -22
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +117 -147
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +4 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +245 -140
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +75 -66
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +43 -30
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +0 -20
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +2 -47
- package/dist/utils.js.map +1 -1
- package/package.json +5 -11
- package/dist/rpc.d.ts +0 -64
- package/dist/rpc.d.ts.map +0 -1
- package/dist/rpc.js +0 -70
- package/dist/rpc.js.map +0 -1
package/README.md
CHANGED
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
|
-
This [Better Auth](https://better-auth.com) plugin enables secure authentication via NEAR wallets following [NEP-413](https://github.com/near/NEPs/blob/master/neps/nep-0413.md) and adds a built-in [NEP-366](https://github.com/near/NEPs/blob/master/neps/nep-0366.md) delegate action relayer so authenticated users can call on-chain contracts gaslessly. It uses [
|
|
16
|
+
This [Better Auth](https://better-auth.com) plugin enables secure authentication via NEAR wallets following [NEP-413](https://github.com/near/NEPs/blob/master/neps/nep-0413.md) and adds a built-in [NEP-366](https://github.com/near/NEPs/blob/master/neps/nep-0366.md) delegate action relayer so authenticated users can call on-chain contracts gaslessly. It uses [near-kit](https://github.com/elliotBraem/near-kit) for RPC queries and transaction broadcasting, and [@hot-labs/near-connect](https://github.com/azbang/near-connect) for wallet connection.
|
|
17
17
|
|
|
18
18
|
## Features
|
|
19
19
|
|
|
20
20
|
- **SIWN authentication** — wallet-based sign-in with automatic single-step/two-step flow detection
|
|
21
21
|
- **Gasless relay** — server relays signed delegate actions on-chain, paying gas from a relayer account
|
|
22
22
|
- **Ephemeral relayer keypair** — auto-generated ED25519 keypair on first startup, private key encrypted with AES-256-GCM in the database, persists across restarts
|
|
23
|
-
- **Profile integration** —
|
|
23
|
+
- **Profile integration** — near-kit profile lookup primary, NEAR Social fallback
|
|
24
24
|
|
|
25
25
|
## Installation
|
|
26
26
|
|
|
@@ -43,7 +43,6 @@ npm install better-near-auth
|
|
|
43
43
|
plugins: [
|
|
44
44
|
siwn({
|
|
45
45
|
recipient: "myapp.com",
|
|
46
|
-
anonymous: true,
|
|
47
46
|
|
|
48
47
|
// Optional: enable gasless relay
|
|
49
48
|
relayer: {
|
|
@@ -120,19 +119,7 @@ export function LoginButton() {
|
|
|
120
119
|
}
|
|
121
120
|
```
|
|
122
121
|
|
|
123
|
-
**Supported wallets
|
|
124
|
-
|
|
125
|
-
### Manual Two-Step Flow (Optional)
|
|
126
|
-
|
|
127
|
-
```ts
|
|
128
|
-
await authClient.requestSignIn.near({
|
|
129
|
-
onSuccess: () => console.log("Wallet connected"),
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
await authClient.signIn.near({
|
|
133
|
-
onSuccess: () => console.log("Signed in!"),
|
|
134
|
-
});
|
|
135
|
-
```
|
|
122
|
+
**Supported wallets:** HOT Wallet, Meteor Wallet, Intear Wallet, MyNearWallet, and more.
|
|
136
123
|
|
|
137
124
|
### Gasless Relay
|
|
138
125
|
|
|
@@ -140,20 +127,19 @@ Once the relayer is configured on the server, authenticated users can call on-ch
|
|
|
140
127
|
|
|
141
128
|
```ts
|
|
142
129
|
// 1. Build a signed delegate action using the wallet's FAK
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
});
|
|
130
|
+
import { Gas } from "near-kit";
|
|
131
|
+
|
|
132
|
+
const signedAction = await authClient.near.buildSignedDelegateAction(
|
|
133
|
+
"myapp.near",
|
|
134
|
+
(builder, receiverId) => builder.functionCall(receiverId, "some_method", { key: "value" }, {
|
|
135
|
+
gas: Gas.Tgas(30),
|
|
136
|
+
attachedDeposit: BigInt(0),
|
|
137
|
+
})
|
|
138
|
+
);
|
|
153
139
|
|
|
154
140
|
// 2. Relay it — the server pays gas
|
|
155
141
|
const result = await authClient.near.relayTransaction({
|
|
156
|
-
|
|
142
|
+
payload: signedAction,
|
|
157
143
|
});
|
|
158
144
|
|
|
159
145
|
console.log("Tx hash:", result.txHash);
|
|
@@ -183,16 +169,12 @@ await authClient.near.disconnect();
|
|
|
183
169
|
| Option | Type | Default | Description |
|
|
184
170
|
|---|---|---|---|
|
|
185
171
|
| `recipient` | `string` | — | NEP-413 recipient identifier (required) |
|
|
186
|
-
| `
|
|
187
|
-
| `emailDomainName` | `string` | recipient | Email domain for non-anonymous accounts |
|
|
188
|
-
| `requireFullAccessKey` | `boolean` | `true` | Require full access keys |
|
|
172
|
+
| `requireFullAccessKey` | `boolean` | `false` | Require full access keys |
|
|
189
173
|
| `getNonce` | `() => Promise<Uint8Array>` | — | Custom nonce generation |
|
|
190
|
-
| `validateNonce` | `(nonce: Uint8Array) => boolean` | — | Custom nonce validation |
|
|
191
|
-
| `validateRecipient` | `(recipient: string) => boolean` | — | Custom recipient validation |
|
|
192
|
-
| `validateMessage` | `(message: string) => boolean` | — | Custom message validation |
|
|
193
174
|
| `getProfile` | `(accountId: string) => Promise<Profile \| null>` | — | Custom profile lookup |
|
|
194
175
|
| `validateLimitedAccessKey` | `(args) => Promise<boolean>` | — | Validate FAK when `requireFullAccessKey` is false |
|
|
195
|
-
| `
|
|
176
|
+
| `apiKey` | `string` | `process.env.FASTNEAR_API_KEY` | API key for RPC |
|
|
177
|
+
| `rpcUrl` | `string` | — | Custom RPC URL (e.g., sandbox, private node) |
|
|
196
178
|
| `relayer` | `RelayerConfig` | — | Relayer configuration (see below) |
|
|
197
179
|
|
|
198
180
|
#### Relayer Configuration
|
|
@@ -201,10 +183,9 @@ await authClient.near.disconnect();
|
|
|
201
183
|
|---|---|---|---|
|
|
202
184
|
| `accountId` | `string` | — | Named relayer account (explicit mode) |
|
|
203
185
|
| `privateKey` | `string` | — | Base64 private key (explicit mode) |
|
|
204
|
-
| `relayTarget` | `string` | FastNear RPC | RPC URL for broadcasting |
|
|
205
186
|
| `whitelistedContracts` | `string[]` | — | Restrict relay to these contracts |
|
|
206
|
-
| `maxGasPerTransaction` | `string` |
|
|
207
|
-
| `maxDepositPerTransaction` | `string` |
|
|
187
|
+
| `maxGasPerTransaction` | `string` | — | Max gas per relayed tx |
|
|
188
|
+
| `maxDepositPerTransaction` | `string` | — | Max deposit per relayed tx |
|
|
208
189
|
|
|
209
190
|
When `accountId` and `privateKey` are omitted, the relayer starts in **ephemeral mode**: an ED25519 keypair is generated on first startup, the implicit account ID is derived from the public key, and the private key is encrypted with AES-256-GCM (using `BETTER_AUTH_SECRET` as KEK via HKDF-SHA256) and stored in the database. The same keypair is recovered on restart.
|
|
210
191
|
|
|
@@ -213,7 +194,7 @@ When `accountId` and `privateKey` are omitted, the relayer starts in **ephemeral
|
|
|
213
194
|
| Option | Type | Default | Description |
|
|
214
195
|
|---|---|---|---|
|
|
215
196
|
| `recipient` | `string` | — | NEP-413 recipient (must match server) |
|
|
216
|
-
| `networkId` | `
|
|
197
|
+
| `networkId` | `"mainnet" \| "testnet"` | `"mainnet"` | NEAR network |
|
|
217
198
|
|
|
218
199
|
## Schema
|
|
219
200
|
|
|
@@ -261,7 +242,7 @@ When `accountId` and `privateKey` are omitted, the relayer starts in **ephemeral
|
|
|
261
242
|
**SIWN**
|
|
262
243
|
- `nonce(params)` — Request a nonce from the server
|
|
263
244
|
- `verify(params)` — Verify an auth token with the server
|
|
264
|
-
- `getProfile(accountId?)` — Get user profile (
|
|
245
|
+
- `getProfile(accountId?)` — Get user profile (near-kit profile lookup → NEAR Social fallback)
|
|
265
246
|
- `getAccountId()` — Currently connected account ID
|
|
266
247
|
- `getState()` — Current wallet state
|
|
267
248
|
- `disconnect()` — Disconnect wallet and clear cached data
|
|
@@ -270,15 +251,14 @@ When `accountId` and `privateKey` are omitted, the relayer starts in **ephemeral
|
|
|
270
251
|
- `listAccounts()` — List all linked NEAR accounts
|
|
271
252
|
|
|
272
253
|
**Relay**
|
|
273
|
-
- `buildSignedDelegateAction(
|
|
274
|
-
- `relayTransaction({
|
|
254
|
+
- `buildSignedDelegateAction(receiverId, buildActions)` — Build + sign a delegate action via wallet FAK
|
|
255
|
+
- `relayTransaction({ payload })` — Submit a signed delegate action to the relayer
|
|
275
256
|
- `getRelayStatus(txHash)` — Check relayed transaction status
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
- `near(callbacks?)` — Connect wallet and cache nonce (two-step flow)
|
|
257
|
+
- `getRelayerInfo()` — Get relayer account info, mode, and balance
|
|
258
|
+
- `relayHistory()` — List relayed transactions for current user
|
|
279
259
|
|
|
280
260
|
### `authClient.signIn`
|
|
281
|
-
- `near(callbacks?)` —
|
|
261
|
+
- `near(callbacks?)` — Connect wallet, sign message, and authenticate (single popup)
|
|
282
262
|
|
|
283
263
|
### Callback Interface
|
|
284
264
|
|
|
@@ -293,11 +273,8 @@ interface AuthCallbacks {
|
|
|
293
273
|
|
|
294
274
|
| Code | Description |
|
|
295
275
|
|---|---|
|
|
296
|
-
| `
|
|
297
|
-
| `
|
|
298
|
-
| `ACCOUNT_MISMATCH` | Cached nonce doesn't match current account |
|
|
299
|
-
| `UNAUTHORIZED_NONCE_REPLAY` | Nonce already used |
|
|
300
|
-
| `UNAUTHORIZED_INVALID_SIGNATURE` | Invalid signature verification |
|
|
276
|
+
| `UNAUTHORIZED_NONCE_REPLAY` | Nonce already used (replay attack detected) |
|
|
277
|
+
| `UNAUTHORIZED` | Generic auth failure (invalid signature, account mismatch, etc.) |
|
|
301
278
|
|
|
302
279
|
### Server Endpoints
|
|
303
280
|
|
|
@@ -312,13 +289,15 @@ interface AuthCallbacks {
|
|
|
312
289
|
| POST | `/near/relay` | Relay a signed delegate action on-chain |
|
|
313
290
|
| GET | `/near/relay-status/:txHash` | Check relayed transaction status |
|
|
314
291
|
| GET | `/near/relayer-info` | Get relayer accountId, mode, balance |
|
|
292
|
+
| GET | `/near/relay-history` | List relayed transactions for current user |
|
|
293
|
+
| POST | `/near/view` | Server-side read-only contract call (authenticated) |
|
|
315
294
|
|
|
316
295
|
## Advanced Configuration
|
|
317
296
|
|
|
318
297
|
```ts title="advanced-auth.ts"
|
|
319
298
|
import { betterAuth } from "better-auth";
|
|
320
299
|
import { siwn } from "better-near-auth";
|
|
321
|
-
import { generateNonce } from "near-
|
|
300
|
+
import { generateNonce } from "near-kit";
|
|
322
301
|
|
|
323
302
|
const usedNonces = new Set<string>();
|
|
324
303
|
|
|
@@ -326,27 +305,10 @@ export const auth = betterAuth({
|
|
|
326
305
|
plugins: [
|
|
327
306
|
siwn({
|
|
328
307
|
recipient: "myapp.com",
|
|
329
|
-
anonymous: false,
|
|
330
|
-
emailDomainName: "myapp.com",
|
|
331
308
|
requireFullAccessKey: false,
|
|
332
309
|
|
|
333
310
|
getNonce: async () => generateNonce(),
|
|
334
311
|
|
|
335
|
-
validateNonce: (nonce: Uint8Array) => {
|
|
336
|
-
const nonceHex = Array.from(nonce).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
337
|
-
if (usedNonces.has(nonceHex)) return false;
|
|
338
|
-
usedNonces.add(nonceHex);
|
|
339
|
-
return true;
|
|
340
|
-
},
|
|
341
|
-
|
|
342
|
-
validateRecipient: (recipient: string) => {
|
|
343
|
-
return ["myapp.com", "staging.myapp.com"].includes(recipient);
|
|
344
|
-
},
|
|
345
|
-
|
|
346
|
-
validateMessage: (message: string) => {
|
|
347
|
-
return message.includes("Sign in to") && message.length > 10;
|
|
348
|
-
},
|
|
349
|
-
|
|
350
312
|
getProfile: async (accountId) => {
|
|
351
313
|
try {
|
|
352
314
|
const res = await fetch(`https://api.myapp.com/profiles/${accountId}`);
|
|
@@ -363,7 +325,7 @@ export const auth = betterAuth({
|
|
|
363
325
|
return recipient ? allowed.includes(recipient) : true;
|
|
364
326
|
},
|
|
365
327
|
|
|
366
|
-
|
|
328
|
+
apiKey: process.env.FASTNEAR_API_KEY,
|
|
367
329
|
|
|
368
330
|
relayer: {
|
|
369
331
|
accountId: "relayer.myapp.near",
|
|
@@ -389,7 +351,7 @@ The plugin detects the network from the account ID:
|
|
|
389
351
|
### NEP-413 Compliance
|
|
390
352
|
- Proper nonce handling prevents replay attacks
|
|
391
353
|
- Message format and recipient validation
|
|
392
|
-
- 15-minute server-side nonce expiration
|
|
354
|
+
- 15-minute server-side nonce expiration with DB replay detection
|
|
393
355
|
|
|
394
356
|
### Relayer Key Security
|
|
395
357
|
- Ephemeral private key encrypted at rest with AES-256-GCM
|
|
@@ -406,8 +368,6 @@ The plugin detects the network from the account ID:
|
|
|
406
368
|
|
|
407
369
|
| Issue | Solution |
|
|
408
370
|
|---|---|
|
|
409
|
-
| "Wallet not connected" | Call `requestSignIn.near()` before `signIn.near()` |
|
|
410
|
-
| "No valid nonce found" | Ensure `requestSignIn.near()` completed; client nonces expire after 5 min |
|
|
411
371
|
| "Invalid or expired nonce" | Server nonces expire after 15 min; check clock sync |
|
|
412
372
|
| "Account ID mismatch" | Verify signed message account ID matches wallet |
|
|
413
373
|
| "Network ID mismatch" | Ensure networkId matches the account's network |
|
|
@@ -454,7 +414,7 @@ pnpm test
|
|
|
454
414
|
- [NEAR Protocol](https://near.org)
|
|
455
415
|
- [NEP-413 Specification](https://github.com/near/NEPs/blob/master/neps/nep-0413.md)
|
|
456
416
|
- [NEP-366 Delegate Actions](https://github.com/near/NEPs/blob/master/neps/nep-0366.md)
|
|
457
|
-
- [
|
|
458
|
-
- [near-
|
|
417
|
+
- [near-kit](https://github.com/elliotBraem/near-kit)
|
|
418
|
+
- [@hot-labs/near-connect](https://github.com/azbang/near-connect)
|
|
459
419
|
- [Example Implementation](https://better-near-auth.near.page)
|
|
460
420
|
- [Contributing Guide](./CONTRIBUTING.md)
|
package/dist/client.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
type
|
|
1
|
+
import { TransactionBuilder } from "near-kit";
|
|
2
|
+
import type { Near as NearType } from "near-kit";
|
|
3
3
|
import type { BetterAuthClientPlugin, BetterAuthClientOptions, BetterFetch, BetterFetchResponse, ClientStore } from "better-auth/client";
|
|
4
4
|
import { atom } from "nanostores";
|
|
5
5
|
import type { siwn } from "./index.js";
|
|
6
|
-
import { type AccountId, type NonceRequestT, type NonceResponseT, type ProfileResponseT, type VerifyRequestT, type VerifyResponseT, type
|
|
6
|
+
import { type AccountId, type NonceRequestT, type NonceResponseT, type ProfileResponseT, type VerifyRequestT, type VerifyResponseT, type RelayResponseT, type RelayStatusResponseT, type NearAccount, type ViewContractRequestT, type ViewContractResponseT, type RelayerInfo, type RelayHistoryResponseT } from "./types.js";
|
|
7
7
|
export interface AuthCallbacks {
|
|
8
8
|
onSuccess?: () => void;
|
|
9
9
|
onError?: (error: Error & {
|
|
@@ -14,20 +14,13 @@ export interface AuthCallbacks {
|
|
|
14
14
|
export interface SIWNClientConfig {
|
|
15
15
|
recipient: string;
|
|
16
16
|
networkId?: "mainnet" | "testnet";
|
|
17
|
-
fastnearApiKey?: string;
|
|
18
|
-
}
|
|
19
|
-
export interface CachedNonceData {
|
|
20
|
-
nonce: string;
|
|
21
|
-
accountId: string;
|
|
22
|
-
publicKey?: string | null;
|
|
23
|
-
networkId: string;
|
|
24
|
-
timestamp: number;
|
|
25
17
|
}
|
|
26
18
|
export interface SIWNClientActions {
|
|
27
19
|
near: {
|
|
28
20
|
nonce: (params: NonceRequestT) => Promise<BetterFetchResponse<NonceResponseT>>;
|
|
29
21
|
verify: (params: VerifyRequestT) => Promise<BetterFetchResponse<VerifyResponseT>>;
|
|
30
22
|
getProfile: (accountId?: AccountId) => Promise<BetterFetchResponse<ProfileResponseT>>;
|
|
23
|
+
view: (params: ViewContractRequestT) => Promise<BetterFetchResponse<ViewContractResponseT>>;
|
|
31
24
|
getAccountId: () => string | null;
|
|
32
25
|
getState: () => {
|
|
33
26
|
accountId: string | null;
|
|
@@ -46,18 +39,16 @@ export interface SIWNClientActions {
|
|
|
46
39
|
listAccounts: () => Promise<BetterFetchResponse<{
|
|
47
40
|
accounts: NearAccount[];
|
|
48
41
|
}>>;
|
|
49
|
-
buildSignedDelegateAction: (
|
|
50
|
-
receiverId: string;
|
|
51
|
-
actions: NearActionInput[];
|
|
52
|
-
}) => Promise<string>;
|
|
42
|
+
buildSignedDelegateAction: (receiverId: string, buildActions: (builder: TransactionBuilder, receiverId: string) => TransactionBuilder) => Promise<string>;
|
|
53
43
|
relayTransaction: (params: {
|
|
54
|
-
|
|
44
|
+
payload: string;
|
|
55
45
|
}) => Promise<BetterFetchResponse<RelayResponseT>>;
|
|
56
46
|
getRelayStatus: (txHash: string) => Promise<BetterFetchResponse<RelayStatusResponseT>>;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
47
|
+
getRelayerInfo: () => Promise<BetterFetchResponse<RelayerInfo & {
|
|
48
|
+
enabled: boolean;
|
|
49
|
+
}>>;
|
|
50
|
+
relayHistory: () => Promise<BetterFetchResponse<RelayHistoryResponseT>>;
|
|
51
|
+
client: NearType;
|
|
61
52
|
};
|
|
62
53
|
signIn: {
|
|
63
54
|
near: (callbacks?: AuthCallbacks) => Promise<void>;
|
|
@@ -72,10 +63,8 @@ export interface SIWNClientPlugin extends BetterAuthClientPlugin {
|
|
|
72
63
|
publicKey: string | null;
|
|
73
64
|
networkId: string;
|
|
74
65
|
} | null>>;
|
|
75
|
-
cachedNonce: ReturnType<typeof atom<CachedNonceData | null>>;
|
|
76
66
|
};
|
|
77
67
|
getActions: ($fetch: BetterFetch, $store: ClientStore, options: BetterAuthClientOptions | undefined) => SIWNClientActions;
|
|
78
68
|
}
|
|
79
69
|
export declare const siwnClient: (config: SIWNClientConfig) => SIWNClientPlugin;
|
|
80
|
-
export {};
|
|
81
70
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|