better-near-auth 0.1.1 → 0.1.2

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 CHANGED
@@ -111,7 +111,7 @@ The SIWN plugin accepts the following configuration options:
111
111
  * **validateRecipient**: Function to validate recipients. Optional, uses exact match by default
112
112
  * **validateMessage**: Function to validate messages. Optional, no validation by default
113
113
  * **getProfile**: Function to fetch user profiles. Optional, uses NEAR Social by default
114
- * **validateFunctionCallKey**: Function to validate function call access keys when `requireFullAccessKey` is false
114
+ * **validateLimitedAccessKey**: Function to validate function call access keys when `requireFullAccessKey` is false
115
115
 
116
116
  ### Client Options
117
117
 
@@ -166,7 +166,6 @@ export const auth = betterAuth({
166
166
  // Optional: Custom profile lookup
167
167
  getProfile: async (accountId) => {
168
168
  // Custom profile logic, falls back to NEAR Social
169
- return null; // Use default NEAR Social lookup
170
169
  },
171
170
  }),
172
171
  ],
@@ -296,7 +295,7 @@ export const auth = betterAuth({
296
295
  },
297
296
 
298
297
  // Validate function call keys against allowed contracts
299
- validateFunctionCallKey: async ({ accountId, publicKey, contractId }) => {
298
+ validateLimitedAccessKey: async ({ accountId, publicKey, contractId }) => {
300
299
  const allowedContracts = ["myapp.near", "social.near"];
301
300
  return contractId ? allowedContracts.includes(contractId) : true;
302
301
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-near-auth",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Sign in with NEAR (SIWN) plugin for Better Auth",
5
5
  "main": "index.ts",
6
6
  "module": "index.ts",
package/src/client.ts CHANGED
@@ -3,6 +3,7 @@ import type { BetterAuthClientPlugin, BetterFetchOption, BetterFetchResponse } f
3
3
  import { sign, type WalletInterface } from "near-sign-verify";
4
4
  import type { siwn } from ".";
5
5
  import { type AccountId, type NonceRequestT, type NonceResponseT, type ProfileResponseT, type VerifyRequestT, type VerifyResponseT } from "./types";
6
+ import type { User } from "better-auth";
6
7
 
7
8
  export interface Signer {
8
9
  accountId(): string | null;
@@ -25,7 +26,7 @@ export interface SIWNClientActions {
25
26
  getProfile: (accountId?: AccountId) => Promise<BetterFetchResponse<ProfileResponseT>>;
26
27
  };
27
28
  signIn: {
28
- near: (params: { recipient: string, signer: Signer }, callbacks?: AuthCallbacks) => Promise<VerifyResponseT>;
29
+ near: (params: { recipient: string, signer: Signer }, callbacks?: AuthCallbacks) => Promise<void>;
29
30
  };
30
31
  }
31
32
 
@@ -66,7 +67,10 @@ export const siwnClient = (config: SIWNClientConfig): SIWNClientPlugin => {
66
67
  },
67
68
  },
68
69
  signIn: {
69
- near: async (params: { recipient: string, signer: Signer }, callbacks?: AuthCallbacks): Promise<VerifyResponseT> => {
70
+ near: async (
71
+ params: { recipient: string, signer: Signer },
72
+ callbacks?: AuthCallbacks
73
+ ): Promise<void> => {
70
74
  try {
71
75
  const { signer, recipient } = params;
72
76
 
@@ -74,32 +78,30 @@ export const siwnClient = (config: SIWNClientConfig): SIWNClientPlugin => {
74
78
  throw new Error("NEAR signer not available");
75
79
  }
76
80
 
77
- // Must be already connected
78
81
  const accountId = signer.accountId();
79
82
  if (!accountId) {
80
83
  throw new Error("Wallet not connected. Please connect your wallet first.");
81
84
  }
82
85
 
83
- // Get nonce for signature
84
86
  const nonceResponse: BetterFetchResponse<NonceResponseT> = await $fetch("/near/nonce", {
85
87
  method: "POST",
86
88
  body: { accountId }
87
89
  });
88
90
 
91
+ if (nonceResponse.error) {
92
+ throw new Error(nonceResponse.error.message || "Failed to get nonce");
93
+ }
94
+
89
95
  const nonce = nonceResponse?.data?.nonce;
90
96
  const message = `Sign in to ${recipient}\n\nAccount ID: ${accountId}\nNonce: ${nonce}`;
91
-
92
- // Convert base64 nonce to Uint8Array for signing
93
97
  const nonceBytes = base64ToBytes(nonce!);
94
98
 
95
- // Sign message
96
99
  const authToken = await sign(message, {
97
100
  signer,
98
101
  recipient,
99
102
  nonce: nonceBytes,
100
103
  });
101
104
 
102
- // Verify signature with backend
103
105
  const verifyResponse: BetterFetchResponse<VerifyResponseT> = await $fetch("/near/verify", {
104
106
  method: "POST",
105
107
  body: {
@@ -108,17 +110,18 @@ export const siwnClient = (config: SIWNClientConfig): SIWNClientPlugin => {
108
110
  }
109
111
  });
110
112
 
113
+ if (verifyResponse.error) {
114
+ throw new Error(verifyResponse.error.message || "Failed to verify signature");
115
+ }
116
+
111
117
  if (!verifyResponse?.data?.success) {
112
118
  throw new Error("Authentication verification failed");
113
119
  }
114
120
 
115
121
  callbacks?.onSuccess?.();
116
- return verifyResponse.data;
117
-
118
122
  } catch (error) {
119
123
  const err = error instanceof Error ? error : new Error(String(error));
120
124
  callbacks?.onError?.(err);
121
- throw err;
122
125
  }
123
126
  }
124
127
  }
package/src/index.ts CHANGED
@@ -38,10 +38,10 @@ export type SIWNPluginOptions =
38
38
  validateRecipient?: (recipient: string) => boolean;
39
39
  validateMessage?: (message: string) => boolean;
40
40
  getProfile?: (accountId: AccountId) => Promise<Profile | null>;
41
- validateFunctionCallKey?: (args: {
41
+ validateLimitedAccessKey?: (args: {
42
42
  accountId: AccountId;
43
43
  publicKey: string;
44
- contractId?: string;
44
+ recipient?: string;
45
45
  }) => Promise<boolean>;
46
46
  }
47
47
  | {
@@ -54,10 +54,10 @@ export type SIWNPluginOptions =
54
54
  validateRecipient?: (recipient: string) => boolean;
55
55
  validateMessage?: (message: string) => boolean;
56
56
  getProfile?: (accountId: AccountId) => Promise<Profile | null>;
57
- validateFunctionCallKey?: (args: {
57
+ validateLimitedAccessKey?: (args: {
58
58
  accountId: AccountId;
59
59
  publicKey: string;
60
- contractId?: string;
60
+ recipient: string;
61
61
  }) => Promise<boolean>;
62
62
  };
63
63
 
@@ -194,13 +194,14 @@ export const siwn = (options: SIWNPluginOptions) =>
194
194
  });
195
195
  }
196
196
 
197
- if (!options.requireFullAccessKey && options.validateFunctionCallKey) {
198
- const isValidFunctionKey = await options.validateFunctionCallKey({
197
+ if (!options.requireFullAccessKey && options.validateLimitedAccessKey) {
198
+ const isValidKey = await options.validateLimitedAccessKey({
199
199
  accountId: result.accountId,
200
200
  publicKey: result.publicKey,
201
- }); // we can validate against an access control contract
201
+ recipient: options.recipient
202
+ }); // we could validate against some access control contract
202
203
 
203
- if (!isValidFunctionKey) {
204
+ if (!isValidKey) {
204
205
  throw new APIError("UNAUTHORIZED", {
205
206
  message: "Unauthorized: Invalid function call access key",
206
207
  status: 401,
package/src/near.test.ts CHANGED
@@ -156,7 +156,7 @@
156
156
  // async verifyMessage({ authToken, expectedRecipient, accountId }) {
157
157
  // return authToken === "valid_token" && expectedRecipient === domain;
158
158
  // },
159
- // async validateFunctionCallKey({ accountId, publicKey }) {
159
+ // async validateLimitedAccessKey({ accountId, publicKey }) {
160
160
  // return accountId === "test.near" && publicKey !== "";
161
161
  // },
162
162
  // }),