@auth-gate/react 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,348 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/server.ts
21
+ var server_exports = {};
22
+ __export(server_exports, {
23
+ createAuthRoutes: () => createAuthRoutes
24
+ });
25
+ module.exports = __toCommonJS(server_exports);
26
+ var import_hono = require("hono");
27
+ var import_cookie = require("hono/cookie");
28
+ var import_core = require("@auth-gate/core");
29
+ function createAuthRoutes(options) {
30
+ const client = (0, import_core.createAuthGateClient)(options);
31
+ const appUrl = options.appUrl;
32
+ async function setSessionCookie(c, user) {
33
+ const encrypted = await client.encryptSession(user);
34
+ const opts = client.getSessionCookieOptions();
35
+ (0, import_cookie.setCookie)(c, client.cookieName, encrypted, {
36
+ httpOnly: opts.httpOnly,
37
+ secure: opts.secure,
38
+ sameSite: opts.sameSite === "lax" ? "Lax" : opts.sameSite === "strict" ? "Strict" : "None",
39
+ maxAge: opts.maxAge,
40
+ path: opts.path
41
+ });
42
+ }
43
+ async function getSessionUser(c) {
44
+ const cookie = (0, import_cookie.getCookie)(c, client.cookieName);
45
+ if (!cookie) return null;
46
+ return client.decryptSession(cookie);
47
+ }
48
+ const routes = new import_hono.Hono().get("/:provider/login", async (c) => {
49
+ const provider = c.req.param("provider");
50
+ if (!import_core.SUPPORTED_PROVIDERS.includes(provider)) {
51
+ return c.json({ error: "Unsupported provider" }, 400);
52
+ }
53
+ const { state, nonce } = await client.createState();
54
+ const nonceOpts = client.getNonceCookieOptions();
55
+ (0, import_cookie.setCookie)(c, client.nonceCookieName, nonce, {
56
+ httpOnly: nonceOpts.httpOnly,
57
+ secure: nonceOpts.secure,
58
+ sameSite: nonceOpts.sameSite === "lax" ? "Lax" : nonceOpts.sameSite === "strict" ? "Strict" : "None",
59
+ maxAge: nonceOpts.maxAge,
60
+ path: nonceOpts.path
61
+ });
62
+ const callbackUrl = `${appUrl}${client.callbackPath}`;
63
+ const authUrl = new URL(
64
+ client.getOAuthUrl(provider, callbackUrl)
65
+ );
66
+ authUrl.searchParams.set("state", state);
67
+ return c.redirect(authUrl.toString());
68
+ }).get("/callback", async (c) => {
69
+ var _a;
70
+ const token = c.req.query("token");
71
+ const state = c.req.query("state");
72
+ const mfaChallenge = c.req.query("mfa_challenge");
73
+ const mfaMethods = c.req.query("mfa_methods");
74
+ const mfaSetupRequired = c.req.query("mfa_setup_required");
75
+ const refreshTokenParam = c.req.query("refresh_token");
76
+ if (mfaChallenge) {
77
+ const mfaUrl = new URL("/mfa-verify", appUrl);
78
+ mfaUrl.searchParams.set("mfa_challenge", mfaChallenge);
79
+ if (mfaMethods) mfaUrl.searchParams.set("mfa_methods", mfaMethods);
80
+ return c.redirect(mfaUrl.toString());
81
+ }
82
+ if (!token) {
83
+ return c.redirect(`${appUrl}/login?error=missing_token`);
84
+ }
85
+ if (state) {
86
+ const nonce = (_a = (0, import_cookie.getCookie)(c, client.nonceCookieName)) != null ? _a : "";
87
+ (0, import_cookie.deleteCookie)(c, client.nonceCookieName, { path: "/" });
88
+ if (!await client.verifyState(state, nonce)) {
89
+ return c.redirect(`${appUrl}/login?error=invalid_state`);
90
+ }
91
+ }
92
+ const result = await client.verifyToken(token);
93
+ if (!result.valid || !result.user) {
94
+ return c.redirect(`${appUrl}/login?error=invalid_token`);
95
+ }
96
+ await setSessionCookie(c, result.user);
97
+ if (refreshTokenParam) {
98
+ (0, import_cookie.setCookie)(c, client.refreshTokenCookieName, refreshTokenParam, {
99
+ httpOnly: true,
100
+ secure: process.env.NODE_ENV === "production",
101
+ sameSite: "Lax",
102
+ maxAge: client.sessionMaxAge,
103
+ path: "/"
104
+ });
105
+ }
106
+ if (mfaSetupRequired) {
107
+ return c.redirect(`${appUrl}/mfa-setup`);
108
+ }
109
+ return c.redirect(`${appUrl}/dashboard`);
110
+ }).post("/email/signup", async (c) => {
111
+ const body = await c.req.json();
112
+ const { email, password, name } = body;
113
+ if (!email || !password) {
114
+ return c.json({ error: "Missing email or password" }, 400);
115
+ }
116
+ const response = await client.emailSignup({
117
+ email,
118
+ password,
119
+ name,
120
+ callbackUrl: `${appUrl}${client.callbackPath}`
121
+ });
122
+ if (!response.ok) {
123
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
124
+ return c.json(error, response.status);
125
+ }
126
+ const data = await response.json().catch(() => ({ error: "Request failed" }));
127
+ const verified = await client.verifyToken(data.token);
128
+ if (!verified.valid || !verified.user) {
129
+ return c.json({ error: "Token verification failed" }, 401);
130
+ }
131
+ await setSessionCookie(c, verified.user);
132
+ return c.json({ success: true, redirect: "/dashboard" });
133
+ }).post("/email/signin", async (c) => {
134
+ const body = await c.req.json();
135
+ const { email, password } = body;
136
+ if (!email || !password) {
137
+ return c.json({ error: "Missing email or password" }, 400);
138
+ }
139
+ const response = await client.emailSignin({
140
+ email,
141
+ password,
142
+ callbackUrl: `${appUrl}${client.callbackPath}`
143
+ });
144
+ if (!response.ok) {
145
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
146
+ return c.json(error, response.status);
147
+ }
148
+ const data = await response.json().catch(() => ({ error: "Request failed" }));
149
+ if (data.mfa_required) {
150
+ return c.json({
151
+ mfa_required: true,
152
+ mfa_challenge: data.mfa_challenge,
153
+ mfa_methods: data.mfa_methods
154
+ });
155
+ }
156
+ const verified = await client.verifyToken(data.token);
157
+ if (!verified.valid || !verified.user) {
158
+ return c.json({ error: "Token verification failed" }, 401);
159
+ }
160
+ await setSessionCookie(c, verified.user);
161
+ if (data.refresh_token) {
162
+ (0, import_cookie.setCookie)(c, client.refreshTokenCookieName, data.refresh_token, {
163
+ httpOnly: true,
164
+ secure: process.env.NODE_ENV === "production",
165
+ sameSite: "Lax",
166
+ maxAge: client.sessionMaxAge,
167
+ path: "/"
168
+ });
169
+ }
170
+ return c.json({
171
+ success: true,
172
+ redirect: data.mfa_setup_required ? "/mfa-setup" : "/dashboard"
173
+ });
174
+ }).post("/email/forgot-password", async (c) => {
175
+ const body = await c.req.json();
176
+ const { email } = body;
177
+ if (!email) {
178
+ return c.json({ error: "Missing email" }, 400);
179
+ }
180
+ const response = await client.emailForgotPassword({
181
+ email,
182
+ callbackUrl: `${appUrl}/reset-password`
183
+ });
184
+ if (!response.ok) {
185
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
186
+ return c.json(error, response.status);
187
+ }
188
+ return c.json({ success: true });
189
+ }).post("/email/reset-password", async (c) => {
190
+ const body = await c.req.json();
191
+ const { token, password } = body;
192
+ if (!token || !password) {
193
+ return c.json({ error: "Missing token or password" }, 400);
194
+ }
195
+ const response = await client.emailResetPassword({ token, password });
196
+ if (!response.ok) {
197
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
198
+ return c.json(error, response.status);
199
+ }
200
+ const data = await response.json().catch(() => ({ error: "Request failed" }));
201
+ if (data.token) {
202
+ const verified = await client.verifyToken(data.token);
203
+ if (verified.valid && verified.user) {
204
+ await setSessionCookie(c, verified.user);
205
+ return c.json({ success: true, redirect: "/dashboard" });
206
+ }
207
+ }
208
+ return c.json({ success: true, redirect: "/login" });
209
+ }).post("/email/verify-code", async (c) => {
210
+ const body = await c.req.json();
211
+ const { email, code } = body;
212
+ if (!email || !code) {
213
+ return c.json({ error: "Missing email or code" }, 400);
214
+ }
215
+ const response = await client.emailVerifyCode({ email, code });
216
+ if (!response.ok) {
217
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
218
+ return c.json(error, response.status);
219
+ }
220
+ return c.json({ success: true, email_verified: true });
221
+ }).post("/magic-link/send", async (c) => {
222
+ const body = await c.req.json();
223
+ const { email } = body;
224
+ if (!email) {
225
+ return c.json({ error: "Missing email" }, 400);
226
+ }
227
+ const response = await client.magicLinkSend({
228
+ email,
229
+ callbackUrl: `${appUrl}${client.callbackPath}`
230
+ });
231
+ if (!response.ok) {
232
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
233
+ return c.json(error, response.status);
234
+ }
235
+ return c.json({ success: true });
236
+ }).post("/sms/send-code", async (c) => {
237
+ const body = await c.req.json();
238
+ const { phone } = body;
239
+ if (!phone) {
240
+ return c.json({ error: "Missing phone number" }, 400);
241
+ }
242
+ const response = await client.smsSendCode({
243
+ phone,
244
+ callbackUrl: `${appUrl}${client.callbackPath}`
245
+ });
246
+ if (!response.ok) {
247
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
248
+ return c.json(error, response.status);
249
+ }
250
+ return c.json({ success: true });
251
+ }).post("/sms/verify-code", async (c) => {
252
+ const body = await c.req.json();
253
+ const { phone, code } = body;
254
+ if (!phone || !code) {
255
+ return c.json({ error: "Missing phone or code" }, 400);
256
+ }
257
+ const response = await client.smsVerifyCode({
258
+ phone,
259
+ code,
260
+ callbackUrl: `${appUrl}${client.callbackPath}`
261
+ });
262
+ if (!response.ok) {
263
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
264
+ return c.json(error, response.status);
265
+ }
266
+ const data = await response.json().catch(() => ({ error: "Request failed" }));
267
+ const verified = await client.verifyToken(data.token);
268
+ if (!verified.valid || !verified.user) {
269
+ return c.json({ error: "Token verification failed" }, 401);
270
+ }
271
+ await setSessionCookie(c, verified.user);
272
+ return c.json({ success: true, redirect: "/dashboard" });
273
+ }).get("/me", async (c) => {
274
+ const user = await getSessionUser(c);
275
+ if (!user) {
276
+ return c.json({ user: null });
277
+ }
278
+ const refreshCookie = (0, import_cookie.getCookie)(c, client.refreshTokenCookieName);
279
+ if (refreshCookie) {
280
+ const result = await client.refreshToken(refreshCookie);
281
+ if (!result) {
282
+ (0, import_cookie.deleteCookie)(c, client.cookieName, { path: "/" });
283
+ (0, import_cookie.deleteCookie)(c, client.refreshTokenCookieName, { path: "/" });
284
+ return c.json({ user: null });
285
+ }
286
+ const verified = await client.verifyToken(result.token);
287
+ if (verified.valid && verified.user) {
288
+ await setSessionCookie(c, verified.user);
289
+ return c.json({ user: verified.user });
290
+ }
291
+ }
292
+ return c.json({ user });
293
+ }).post("/mfa/verify", async (c) => {
294
+ const body = await c.req.json();
295
+ const { challenge, code, method } = body;
296
+ if (!challenge || !code || !method) {
297
+ return c.json({ error: "Missing challenge, code, or method" }, 400);
298
+ }
299
+ const response = await client.mfaVerify({ challenge, code, method });
300
+ if (!response.ok) {
301
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
302
+ return c.json(error, response.status);
303
+ }
304
+ const data = await response.json();
305
+ const verified = await client.verifyToken(data.token);
306
+ if (!verified.valid || !verified.user) {
307
+ return c.json({ error: "Token verification failed" }, 401);
308
+ }
309
+ await setSessionCookie(c, verified.user);
310
+ if (data.refresh_token) {
311
+ (0, import_cookie.setCookie)(c, client.refreshTokenCookieName, data.refresh_token, {
312
+ httpOnly: true,
313
+ secure: process.env.NODE_ENV === "production",
314
+ sameSite: "Lax",
315
+ maxAge: client.sessionMaxAge,
316
+ path: "/"
317
+ });
318
+ }
319
+ return c.json({ success: true, redirect: "/dashboard" });
320
+ }).post("/refresh", async (c) => {
321
+ const refreshCookie = (0, import_cookie.getCookie)(c, client.refreshTokenCookieName);
322
+ if (!refreshCookie) {
323
+ return c.json({ error: "No refresh token" }, 401);
324
+ }
325
+ const result = await client.refreshToken(refreshCookie);
326
+ if (!result) {
327
+ return c.json({ error: "Invalid refresh token" }, 401);
328
+ }
329
+ const verified = await client.verifyToken(result.token);
330
+ if (verified.valid && verified.user) {
331
+ await setSessionCookie(c, verified.user);
332
+ }
333
+ return c.json({ success: true, token: result.token });
334
+ }).post("/logout", async (c) => {
335
+ const refreshCookie = (0, import_cookie.getCookie)(c, client.refreshTokenCookieName);
336
+ if (refreshCookie) {
337
+ await client.revokeSession(refreshCookie);
338
+ (0, import_cookie.deleteCookie)(c, client.refreshTokenCookieName, { path: "/" });
339
+ }
340
+ (0, import_cookie.deleteCookie)(c, client.cookieName, { path: "/" });
341
+ return c.json({ success: true });
342
+ });
343
+ return routes;
344
+ }
345
+ // Annotate the CommonJS export names for ESM import in node:
346
+ 0 && (module.exports = {
347
+ createAuthRoutes
348
+ });
@@ -0,0 +1,316 @@
1
+ import * as hono_hono_base from 'hono/hono-base';
2
+ import * as hono_utils_http_status from 'hono/utils/http-status';
3
+ import * as hono_types from 'hono/types';
4
+ import { AuthGateConfig } from '@auth-gate/core';
5
+
6
+ /**
7
+ * Configuration for {@link createAuthRoutes}.
8
+ * Extends {@link AuthGateConfig} with the app's public URL.
9
+ */
10
+ interface AuthRoutesOptions extends AuthGateConfig {
11
+ /** Your app's public URL (e.g. `"http://localhost:5173"`). Used to build callback URLs. */
12
+ appUrl: string;
13
+ }
14
+ /**
15
+ * Create a Hono router with all AuthGate auth endpoints.
16
+ *
17
+ * Mount the returned router at `/api/auth` (or any prefix you prefer):
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { Hono } from "hono";
22
+ * import { createAuthRoutes } from "@auth-gate/react/server";
23
+ *
24
+ * const app = new Hono();
25
+ * const auth = createAuthRoutes({
26
+ * apiKey: process.env.AUTHGATE_API_KEY!,
27
+ * projectId: process.env.AUTHGATE_PROJECT_ID!,
28
+ * baseUrl: process.env.AUTHGATE_URL!,
29
+ * sessionSecret: process.env.SESSION_SECRET!,
30
+ * appUrl: "http://localhost:5173",
31
+ * });
32
+ *
33
+ * app.route("/api/auth", auth);
34
+ * ```
35
+ *
36
+ * @param options - AuthGate config plus `appUrl`.
37
+ * @returns A Hono router instance with all auth routes.
38
+ */
39
+ declare function createAuthRoutes(options: AuthRoutesOptions): hono_hono_base.HonoBase<hono_types.BlankEnv, {
40
+ "/:provider/login": {
41
+ $get: {
42
+ input: {
43
+ param: {
44
+ provider: string;
45
+ };
46
+ };
47
+ output: {
48
+ error: string;
49
+ };
50
+ outputFormat: "json";
51
+ status: 400;
52
+ } | {
53
+ input: {
54
+ param: {
55
+ provider: string;
56
+ };
57
+ };
58
+ output: undefined;
59
+ outputFormat: "redirect";
60
+ status: 302;
61
+ };
62
+ };
63
+ } & {
64
+ "/callback": {
65
+ $get: {
66
+ input: {};
67
+ output: undefined;
68
+ outputFormat: "redirect";
69
+ status: 302;
70
+ };
71
+ };
72
+ } & {
73
+ "/email/signup": {
74
+ $post: {
75
+ input: {};
76
+ output: {};
77
+ outputFormat: "json";
78
+ status: 400;
79
+ } | {
80
+ input: {};
81
+ output: {
82
+ error: string;
83
+ };
84
+ outputFormat: "json";
85
+ status: 401;
86
+ } | {
87
+ input: {};
88
+ output: {
89
+ success: true;
90
+ redirect: string;
91
+ };
92
+ outputFormat: "json";
93
+ status: hono_utils_http_status.ContentfulStatusCode;
94
+ };
95
+ };
96
+ } & {
97
+ "/email/signin": {
98
+ $post: {
99
+ input: {};
100
+ output: {};
101
+ outputFormat: "json";
102
+ status: 400;
103
+ } | {
104
+ input: {};
105
+ output: {
106
+ mfa_required: true;
107
+ mfa_challenge: any;
108
+ mfa_methods: any;
109
+ };
110
+ outputFormat: "json";
111
+ status: hono_utils_http_status.ContentfulStatusCode;
112
+ } | {
113
+ input: {};
114
+ output: {
115
+ error: string;
116
+ };
117
+ outputFormat: "json";
118
+ status: 401;
119
+ } | {
120
+ input: {};
121
+ output: {
122
+ success: true;
123
+ redirect: string;
124
+ };
125
+ outputFormat: "json";
126
+ status: hono_utils_http_status.ContentfulStatusCode;
127
+ };
128
+ };
129
+ } & {
130
+ "/email/forgot-password": {
131
+ $post: {
132
+ input: {};
133
+ output: {};
134
+ outputFormat: "json";
135
+ status: 400;
136
+ } | {
137
+ input: {};
138
+ output: {
139
+ success: true;
140
+ };
141
+ outputFormat: "json";
142
+ status: hono_utils_http_status.ContentfulStatusCode;
143
+ };
144
+ };
145
+ } & {
146
+ "/email/reset-password": {
147
+ $post: {
148
+ input: {};
149
+ output: {};
150
+ outputFormat: "json";
151
+ status: 400;
152
+ } | {
153
+ input: {};
154
+ output: {
155
+ success: true;
156
+ redirect: string;
157
+ };
158
+ outputFormat: "json";
159
+ status: hono_utils_http_status.ContentfulStatusCode;
160
+ };
161
+ };
162
+ } & {
163
+ "/email/verify-code": {
164
+ $post: {
165
+ input: {};
166
+ output: {};
167
+ outputFormat: "json";
168
+ status: 400;
169
+ } | {
170
+ input: {};
171
+ output: {
172
+ success: true;
173
+ email_verified: true;
174
+ };
175
+ outputFormat: "json";
176
+ status: hono_utils_http_status.ContentfulStatusCode;
177
+ };
178
+ };
179
+ } & {
180
+ "/magic-link/send": {
181
+ $post: {
182
+ input: {};
183
+ output: {};
184
+ outputFormat: "json";
185
+ status: 400;
186
+ } | {
187
+ input: {};
188
+ output: {
189
+ success: true;
190
+ };
191
+ outputFormat: "json";
192
+ status: hono_utils_http_status.ContentfulStatusCode;
193
+ };
194
+ };
195
+ } & {
196
+ "/sms/send-code": {
197
+ $post: {
198
+ input: {};
199
+ output: {};
200
+ outputFormat: "json";
201
+ status: 400;
202
+ } | {
203
+ input: {};
204
+ output: {
205
+ success: true;
206
+ };
207
+ outputFormat: "json";
208
+ status: hono_utils_http_status.ContentfulStatusCode;
209
+ };
210
+ };
211
+ } & {
212
+ "/sms/verify-code": {
213
+ $post: {
214
+ input: {};
215
+ output: {};
216
+ outputFormat: "json";
217
+ status: 400;
218
+ } | {
219
+ input: {};
220
+ output: {
221
+ error: string;
222
+ };
223
+ outputFormat: "json";
224
+ status: 401;
225
+ } | {
226
+ input: {};
227
+ output: {
228
+ success: true;
229
+ redirect: string;
230
+ };
231
+ outputFormat: "json";
232
+ status: hono_utils_http_status.ContentfulStatusCode;
233
+ };
234
+ };
235
+ } & {
236
+ "/me": {
237
+ $get: {
238
+ input: {};
239
+ output: {
240
+ user: null;
241
+ };
242
+ outputFormat: "json";
243
+ status: hono_utils_http_status.ContentfulStatusCode;
244
+ } | {
245
+ input: {};
246
+ output: {
247
+ user: {
248
+ id: string;
249
+ email: string | null;
250
+ phone: string | null;
251
+ name: string | null;
252
+ picture: string | null;
253
+ provider: string;
254
+ };
255
+ };
256
+ outputFormat: "json";
257
+ status: hono_utils_http_status.ContentfulStatusCode;
258
+ };
259
+ };
260
+ } & {
261
+ "/mfa/verify": {
262
+ $post: {
263
+ input: {};
264
+ output: {};
265
+ outputFormat: "json";
266
+ status: 400;
267
+ } | {
268
+ input: {};
269
+ output: {
270
+ error: string;
271
+ };
272
+ outputFormat: "json";
273
+ status: 401;
274
+ } | {
275
+ input: {};
276
+ output: {
277
+ success: true;
278
+ redirect: string;
279
+ };
280
+ outputFormat: "json";
281
+ status: hono_utils_http_status.ContentfulStatusCode;
282
+ };
283
+ };
284
+ } & {
285
+ "/refresh": {
286
+ $post: {
287
+ input: {};
288
+ output: {
289
+ error: string;
290
+ };
291
+ outputFormat: "json";
292
+ status: 401;
293
+ } | {
294
+ input: {};
295
+ output: {
296
+ success: true;
297
+ token: string;
298
+ };
299
+ outputFormat: "json";
300
+ status: hono_utils_http_status.ContentfulStatusCode;
301
+ };
302
+ };
303
+ } & {
304
+ "/logout": {
305
+ $post: {
306
+ input: {};
307
+ output: {
308
+ success: true;
309
+ };
310
+ outputFormat: "json";
311
+ status: hono_utils_http_status.ContentfulStatusCode;
312
+ };
313
+ };
314
+ }, "/", "/logout">;
315
+
316
+ export { type AuthRoutesOptions, createAuthRoutes };