transactional-auth-next 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 ADDED
@@ -0,0 +1,312 @@
1
+ # transactional-auth-next
2
+
3
+ Next.js SDK for Transactional Auth - OpenID Connect authentication with full support for App Router, Server Components, and Middleware.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install transactional-auth-next
9
+ # or
10
+ yarn add transactional-auth-next
11
+ # or
12
+ pnpm add transactional-auth-next
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ### 1. Set Environment Variables
18
+
19
+ ```env
20
+ TRANSACTIONAL_AUTH_DOMAIN=auth.usetransactional.com
21
+ TRANSACTIONAL_AUTH_CLIENT_ID=your-client-id
22
+ TRANSACTIONAL_AUTH_CLIENT_SECRET=your-client-secret
23
+ TRANSACTIONAL_AUTH_BASE_URL=http://localhost:3000
24
+ ```
25
+
26
+ ### 2. Create API Routes
27
+
28
+ Create a catch-all route handler for authentication:
29
+
30
+ ```ts
31
+ // app/api/auth/[...auth]/route.ts
32
+ import {
33
+ handleLogin,
34
+ handleCallback,
35
+ handleLogout,
36
+ handleSession,
37
+ } from 'transactional-auth-next/server';
38
+ import { NextRequest } from 'next/server';
39
+
40
+ export async function GET(
41
+ request: NextRequest,
42
+ { params }: { params: { auth: string[] } }
43
+ ) {
44
+ const route = params.auth[0];
45
+
46
+ switch (route) {
47
+ case 'login':
48
+ return handleLogin()(request);
49
+ case 'callback':
50
+ return handleCallback()(request);
51
+ case 'logout':
52
+ return handleLogout()(request);
53
+ case 'session':
54
+ return handleSession()(request);
55
+ default:
56
+ return new Response('Not found', { status: 404 });
57
+ }
58
+ }
59
+ ```
60
+
61
+ ### 3. Add Provider to Layout
62
+
63
+ ```tsx
64
+ // app/layout.tsx
65
+ import { TransactionalAuthProvider } from 'transactional-auth-next/client';
66
+
67
+ export default function RootLayout({
68
+ children,
69
+ }: {
70
+ children: React.ReactNode;
71
+ }) {
72
+ return (
73
+ <html lang="en">
74
+ <body>
75
+ <TransactionalAuthProvider>{children}</TransactionalAuthProvider>
76
+ </body>
77
+ </html>
78
+ );
79
+ }
80
+ ```
81
+
82
+ ### 4. Use in Components
83
+
84
+ **Server Component:**
85
+
86
+ ```tsx
87
+ // app/page.tsx
88
+ import { getSession, getUser } from 'transactional-auth-next/server';
89
+
90
+ export default async function Page() {
91
+ const session = await getSession();
92
+
93
+ if (!session) {
94
+ return <p>Not logged in</p>;
95
+ }
96
+
97
+ return (
98
+ <div>
99
+ <h1>Welcome, {session.user.name}</h1>
100
+ <p>Email: {session.user.email}</p>
101
+ </div>
102
+ );
103
+ }
104
+ ```
105
+
106
+ **Client Component:**
107
+
108
+ ```tsx
109
+ // components/login-button.tsx
110
+ 'use client';
111
+
112
+ import { useAuth } from 'transactional-auth-next/client';
113
+
114
+ export function LoginButton() {
115
+ const { user, isLoading, login, logout } = useAuth();
116
+
117
+ if (isLoading) {
118
+ return <div>Loading...</div>;
119
+ }
120
+
121
+ if (user) {
122
+ return (
123
+ <div>
124
+ <span>Hello, {user.name}</span>
125
+ <button onClick={() => logout()}>Logout</button>
126
+ </div>
127
+ );
128
+ }
129
+
130
+ return <button onClick={() => login()}>Login</button>;
131
+ }
132
+ ```
133
+
134
+ ## Protecting Routes with Middleware
135
+
136
+ ```ts
137
+ // middleware.ts
138
+ import { createAuthMiddleware } from 'transactional-auth-next/middleware';
139
+
140
+ export default createAuthMiddleware({
141
+ protectedPaths: ['/dashboard/*', '/settings/*', '/api/protected/*'],
142
+ publicPaths: ['/', '/about', '/api/public/*'],
143
+ });
144
+
145
+ export const config = {
146
+ matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
147
+ };
148
+ ```
149
+
150
+ ## Protecting API Routes
151
+
152
+ ```ts
153
+ // app/api/protected/route.ts
154
+ import { withAuth } from 'transactional-auth-next/middleware';
155
+ import { NextRequest } from 'next/server';
156
+
157
+ export const GET = withAuth(async (request, session) => {
158
+ return Response.json({
159
+ message: 'This is protected data',
160
+ user: session.user,
161
+ });
162
+ });
163
+ ```
164
+
165
+ ## API Reference
166
+
167
+ ### Server Functions (`transactional-auth-next/server`)
168
+
169
+ #### `getSession()`
170
+
171
+ Get the current session in a Server Component.
172
+
173
+ ```tsx
174
+ const session = await getSession();
175
+ // session?.user, session?.accessToken, session?.expiresAt
176
+ ```
177
+
178
+ #### `getUser()`
179
+
180
+ Get the current user in a Server Component.
181
+
182
+ ```tsx
183
+ const user = await getUser();
184
+ // user?.sub, user?.email, user?.name
185
+ ```
186
+
187
+ #### `getAccessToken()`
188
+
189
+ Get the access token for API calls.
190
+
191
+ ```tsx
192
+ const token = await getAccessToken();
193
+ ```
194
+
195
+ #### `isAuthenticated()`
196
+
197
+ Check if user is authenticated.
198
+
199
+ ```tsx
200
+ const authenticated = await isAuthenticated();
201
+ ```
202
+
203
+ #### Route Handlers
204
+
205
+ - `handleLogin(options?)` - Redirects to auth server
206
+ - `handleCallback()` - Handles OAuth callback
207
+ - `handleLogout(options?)` - Logs out user
208
+ - `handleSession()` - Returns current session as JSON
209
+
210
+ ### Client Functions (`transactional-auth-next/client`)
211
+
212
+ #### `TransactionalAuthProvider`
213
+
214
+ Wrap your app to provide auth context.
215
+
216
+ ```tsx
217
+ <TransactionalAuthProvider initialSession={session}>
218
+ {children}
219
+ </TransactionalAuthProvider>
220
+ ```
221
+
222
+ #### `useAuth()`
223
+
224
+ Hook for auth state and methods.
225
+
226
+ ```tsx
227
+ const { user, isLoading, isAuthenticated, login, logout, refreshSession } = useAuth();
228
+ ```
229
+
230
+ #### `useUser()`
231
+
232
+ Hook for just user data.
233
+
234
+ ```tsx
235
+ const { user, isLoading } = useUser();
236
+ ```
237
+
238
+ ### Middleware (`transactional-auth-next/middleware`)
239
+
240
+ #### `createAuthMiddleware(config)`
241
+
242
+ Create Next.js middleware for route protection.
243
+
244
+ ```ts
245
+ createAuthMiddleware({
246
+ protectedPaths: ['/dashboard/*'],
247
+ publicPaths: ['/'],
248
+ loginUrl: '/api/auth/login',
249
+ onUnauthorized: (request) => NextResponse.redirect('/login'),
250
+ });
251
+ ```
252
+
253
+ #### `withAuth(handler, options?)`
254
+
255
+ Protect individual API routes.
256
+
257
+ ```ts
258
+ export const GET = withAuth(async (request, session) => {
259
+ // session is guaranteed to exist
260
+ return Response.json({ user: session.user });
261
+ });
262
+ ```
263
+
264
+ ## Configuration
265
+
266
+ ### Environment Variables
267
+
268
+ | Variable | Required | Description |
269
+ |----------|----------|-------------|
270
+ | `TRANSACTIONAL_AUTH_DOMAIN` | Yes | Auth domain |
271
+ | `TRANSACTIONAL_AUTH_CLIENT_ID` | Yes | Client ID |
272
+ | `TRANSACTIONAL_AUTH_CLIENT_SECRET` | Server-side | Client secret |
273
+ | `TRANSACTIONAL_AUTH_BASE_URL` | Yes | Your app URL |
274
+
275
+ ### Programmatic Configuration
276
+
277
+ ```ts
278
+ import { initTransactionalAuth } from 'transactional-auth-next';
279
+
280
+ initTransactionalAuth({
281
+ domain: 'auth.usetransactional.com',
282
+ clientId: 'your-client-id',
283
+ clientSecret: 'your-client-secret',
284
+ baseUrl: 'http://localhost:3000',
285
+ scope: 'openid profile email',
286
+ audience: 'https://api.example.com',
287
+ cookieName: 'my_session',
288
+ cookieOptions: {
289
+ secure: true,
290
+ sameSite: 'lax',
291
+ maxAge: 7 * 24 * 60 * 60,
292
+ },
293
+ });
294
+ ```
295
+
296
+ ## TypeScript
297
+
298
+ Full TypeScript support with exported types:
299
+
300
+ ```ts
301
+ import type {
302
+ TransactionalAuthConfig,
303
+ TransactionalAuthUser,
304
+ Session,
305
+ LoginOptions,
306
+ LogoutOptions,
307
+ } from 'transactional-auth-next';
308
+ ```
309
+
310
+ ## License
311
+
312
+ MIT
@@ -0,0 +1,52 @@
1
+ // src/config.ts
2
+ var globalConfig = null;
3
+ function initTransactionalAuth(config) {
4
+ globalConfig = {
5
+ ...config,
6
+ scope: config.scope || "openid profile email",
7
+ cookieName: config.cookieName || "transactional_session",
8
+ cookieOptions: {
9
+ secure: config.cookieOptions?.secure ?? process.env.NODE_ENV === "production",
10
+ sameSite: config.cookieOptions?.sameSite ?? "lax",
11
+ maxAge: config.cookieOptions?.maxAge ?? 7 * 24 * 60 * 60
12
+ // 7 days
13
+ }
14
+ };
15
+ }
16
+ function getConfig() {
17
+ if (!globalConfig) {
18
+ const domain = process.env.TRANSACTIONAL_AUTH_DOMAIN || process.env.NEXT_PUBLIC_TRANSACTIONAL_AUTH_DOMAIN;
19
+ const clientId = process.env.TRANSACTIONAL_AUTH_CLIENT_ID || process.env.NEXT_PUBLIC_TRANSACTIONAL_AUTH_CLIENT_ID;
20
+ const clientSecret = process.env.TRANSACTIONAL_AUTH_CLIENT_SECRET;
21
+ const baseUrl = process.env.TRANSACTIONAL_AUTH_BASE_URL || process.env.NEXT_PUBLIC_APP_URL;
22
+ if (domain && clientId) {
23
+ globalConfig = {
24
+ domain,
25
+ clientId,
26
+ clientSecret,
27
+ baseUrl,
28
+ scope: "openid profile email",
29
+ cookieName: "transactional_session",
30
+ cookieOptions: {
31
+ secure: process.env.NODE_ENV === "production",
32
+ sameSite: "lax",
33
+ maxAge: 7 * 24 * 60 * 60
34
+ }
35
+ };
36
+ return globalConfig;
37
+ }
38
+ throw new Error(
39
+ "Transactional Auth not initialized. Call initTransactionalAuth() or set environment variables."
40
+ );
41
+ }
42
+ return globalConfig;
43
+ }
44
+ function isInitialized() {
45
+ return globalConfig !== null;
46
+ }
47
+
48
+ export {
49
+ initTransactionalAuth,
50
+ getConfig,
51
+ isInitialized
52
+ };
@@ -0,0 +1,73 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import { a as TransactionalAuthUser } from '../types-D3JPYyLl.mjs';
4
+
5
+ interface AuthContextValue {
6
+ user: TransactionalAuthUser | null;
7
+ isLoading: boolean;
8
+ isAuthenticated: boolean;
9
+ login: (returnTo?: string) => void;
10
+ logout: (returnTo?: string) => void;
11
+ refreshSession: () => Promise<void>;
12
+ }
13
+ interface TransactionalAuthProviderProps {
14
+ children: React.ReactNode;
15
+ /** Initial session from server (optional) */
16
+ initialSession?: {
17
+ user: TransactionalAuthUser;
18
+ expiresAt: number;
19
+ } | null;
20
+ }
21
+ /**
22
+ * Client-side auth provider for Next.js.
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * // app/layout.tsx
27
+ * import { TransactionalAuthProvider } from 'transactional-auth-next/client';
28
+ *
29
+ * export default function RootLayout({ children }) {
30
+ * return (
31
+ * <html>
32
+ * <body>
33
+ * <TransactionalAuthProvider>
34
+ * {children}
35
+ * </TransactionalAuthProvider>
36
+ * </body>
37
+ * </html>
38
+ * );
39
+ * }
40
+ * ```
41
+ */
42
+ declare function TransactionalAuthProvider({ children, initialSession, }: TransactionalAuthProviderProps): react_jsx_runtime.JSX.Element;
43
+ /**
44
+ * Hook to access auth state and methods in Client Components.
45
+ *
46
+ * @example
47
+ * ```tsx
48
+ * 'use client';
49
+ * import { useAuth } from 'transactional-auth-next/client';
50
+ *
51
+ * export function LoginButton() {
52
+ * const { user, isLoading, login, logout } = useAuth();
53
+ *
54
+ * if (isLoading) return <div>Loading...</div>;
55
+ *
56
+ * if (user) {
57
+ * return <button onClick={() => logout()}>Logout</button>;
58
+ * }
59
+ *
60
+ * return <button onClick={() => login()}>Login</button>;
61
+ * }
62
+ * ```
63
+ */
64
+ declare function useAuth(): AuthContextValue;
65
+ /**
66
+ * Hook to get the current user in Client Components.
67
+ */
68
+ declare function useUser(): {
69
+ user: TransactionalAuthUser | null;
70
+ isLoading: boolean;
71
+ };
72
+
73
+ export { TransactionalAuthProvider, useAuth, useUser };
@@ -0,0 +1,73 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import { a as TransactionalAuthUser } from '../types-D3JPYyLl.js';
4
+
5
+ interface AuthContextValue {
6
+ user: TransactionalAuthUser | null;
7
+ isLoading: boolean;
8
+ isAuthenticated: boolean;
9
+ login: (returnTo?: string) => void;
10
+ logout: (returnTo?: string) => void;
11
+ refreshSession: () => Promise<void>;
12
+ }
13
+ interface TransactionalAuthProviderProps {
14
+ children: React.ReactNode;
15
+ /** Initial session from server (optional) */
16
+ initialSession?: {
17
+ user: TransactionalAuthUser;
18
+ expiresAt: number;
19
+ } | null;
20
+ }
21
+ /**
22
+ * Client-side auth provider for Next.js.
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * // app/layout.tsx
27
+ * import { TransactionalAuthProvider } from 'transactional-auth-next/client';
28
+ *
29
+ * export default function RootLayout({ children }) {
30
+ * return (
31
+ * <html>
32
+ * <body>
33
+ * <TransactionalAuthProvider>
34
+ * {children}
35
+ * </TransactionalAuthProvider>
36
+ * </body>
37
+ * </html>
38
+ * );
39
+ * }
40
+ * ```
41
+ */
42
+ declare function TransactionalAuthProvider({ children, initialSession, }: TransactionalAuthProviderProps): react_jsx_runtime.JSX.Element;
43
+ /**
44
+ * Hook to access auth state and methods in Client Components.
45
+ *
46
+ * @example
47
+ * ```tsx
48
+ * 'use client';
49
+ * import { useAuth } from 'transactional-auth-next/client';
50
+ *
51
+ * export function LoginButton() {
52
+ * const { user, isLoading, login, logout } = useAuth();
53
+ *
54
+ * if (isLoading) return <div>Loading...</div>;
55
+ *
56
+ * if (user) {
57
+ * return <button onClick={() => logout()}>Logout</button>;
58
+ * }
59
+ *
60
+ * return <button onClick={() => login()}>Login</button>;
61
+ * }
62
+ * ```
63
+ */
64
+ declare function useAuth(): AuthContextValue;
65
+ /**
66
+ * Hook to get the current user in Client Components.
67
+ */
68
+ declare function useUser(): {
69
+ user: TransactionalAuthUser | null;
70
+ isLoading: boolean;
71
+ };
72
+
73
+ export { TransactionalAuthProvider, useAuth, useUser };
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/client/index.ts
31
+ var client_exports = {};
32
+ __export(client_exports, {
33
+ TransactionalAuthProvider: () => TransactionalAuthProvider,
34
+ useAuth: () => useAuth,
35
+ useUser: () => useUser
36
+ });
37
+ module.exports = __toCommonJS(client_exports);
38
+
39
+ // src/client/provider.tsx
40
+ var React = __toESM(require("react"));
41
+ var import_jsx_runtime = require("react/jsx-runtime");
42
+ var AuthContext = React.createContext(null);
43
+ function TransactionalAuthProvider({
44
+ children,
45
+ initialSession
46
+ }) {
47
+ const [user, setUser] = React.useState(
48
+ initialSession?.user || null
49
+ );
50
+ const [isLoading, setIsLoading] = React.useState(!initialSession);
51
+ React.useEffect(() => {
52
+ if (!initialSession) {
53
+ fetchSession();
54
+ }
55
+ }, [initialSession]);
56
+ const fetchSession = async () => {
57
+ try {
58
+ const response = await fetch("/api/auth/session");
59
+ const data = await response.json();
60
+ setUser(data.session?.user || null);
61
+ } catch {
62
+ setUser(null);
63
+ } finally {
64
+ setIsLoading(false);
65
+ }
66
+ };
67
+ const login = (returnTo) => {
68
+ const url = new URL("/api/auth/login", window.location.origin);
69
+ if (returnTo) {
70
+ url.searchParams.set("returnTo", returnTo);
71
+ }
72
+ window.location.href = url.toString();
73
+ };
74
+ const logout = (returnTo) => {
75
+ const url = new URL("/api/auth/logout", window.location.origin);
76
+ if (returnTo) {
77
+ url.searchParams.set("returnTo", returnTo);
78
+ }
79
+ window.location.href = url.toString();
80
+ };
81
+ const refreshSession = async () => {
82
+ await fetchSession();
83
+ };
84
+ const value = {
85
+ user,
86
+ isLoading,
87
+ isAuthenticated: !!user,
88
+ login,
89
+ logout,
90
+ refreshSession
91
+ };
92
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthContext.Provider, { value, children });
93
+ }
94
+ function useAuth() {
95
+ const context = React.useContext(AuthContext);
96
+ if (!context) {
97
+ throw new Error("useAuth must be used within a TransactionalAuthProvider");
98
+ }
99
+ return context;
100
+ }
101
+ function useUser() {
102
+ const { user, isLoading } = useAuth();
103
+ return { user, isLoading };
104
+ }
105
+ // Annotate the CommonJS export names for ESM import in node:
106
+ 0 && (module.exports = {
107
+ TransactionalAuthProvider,
108
+ useAuth,
109
+ useUser
110
+ });
@@ -0,0 +1,71 @@
1
+ // src/client/provider.tsx
2
+ import * as React from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ var AuthContext = React.createContext(null);
5
+ function TransactionalAuthProvider({
6
+ children,
7
+ initialSession
8
+ }) {
9
+ const [user, setUser] = React.useState(
10
+ initialSession?.user || null
11
+ );
12
+ const [isLoading, setIsLoading] = React.useState(!initialSession);
13
+ React.useEffect(() => {
14
+ if (!initialSession) {
15
+ fetchSession();
16
+ }
17
+ }, [initialSession]);
18
+ const fetchSession = async () => {
19
+ try {
20
+ const response = await fetch("/api/auth/session");
21
+ const data = await response.json();
22
+ setUser(data.session?.user || null);
23
+ } catch {
24
+ setUser(null);
25
+ } finally {
26
+ setIsLoading(false);
27
+ }
28
+ };
29
+ const login = (returnTo) => {
30
+ const url = new URL("/api/auth/login", window.location.origin);
31
+ if (returnTo) {
32
+ url.searchParams.set("returnTo", returnTo);
33
+ }
34
+ window.location.href = url.toString();
35
+ };
36
+ const logout = (returnTo) => {
37
+ const url = new URL("/api/auth/logout", window.location.origin);
38
+ if (returnTo) {
39
+ url.searchParams.set("returnTo", returnTo);
40
+ }
41
+ window.location.href = url.toString();
42
+ };
43
+ const refreshSession = async () => {
44
+ await fetchSession();
45
+ };
46
+ const value = {
47
+ user,
48
+ isLoading,
49
+ isAuthenticated: !!user,
50
+ login,
51
+ logout,
52
+ refreshSession
53
+ };
54
+ return /* @__PURE__ */ jsx(AuthContext.Provider, { value, children });
55
+ }
56
+ function useAuth() {
57
+ const context = React.useContext(AuthContext);
58
+ if (!context) {
59
+ throw new Error("useAuth must be used within a TransactionalAuthProvider");
60
+ }
61
+ return context;
62
+ }
63
+ function useUser() {
64
+ const { user, isLoading } = useAuth();
65
+ return { user, isLoading };
66
+ }
67
+ export {
68
+ TransactionalAuthProvider,
69
+ useAuth,
70
+ useUser
71
+ };
@@ -0,0 +1,23 @@
1
+ import { T as TransactionalAuthConfig } from './types-D3JPYyLl.mjs';
2
+ export { L as LoginOptions, b as LogoutOptions, S as Session, a as TransactionalAuthUser } from './types-D3JPYyLl.mjs';
3
+
4
+ /**
5
+ * Transactional Auth Next - Configuration
6
+ */
7
+
8
+ /**
9
+ * Initialize the Transactional Auth SDK with your configuration.
10
+ * Call this once in your application, typically in a layout or middleware.
11
+ */
12
+ declare function initTransactionalAuth(config: TransactionalAuthConfig): void;
13
+ /**
14
+ * Get the current configuration.
15
+ * Throws if not initialized.
16
+ */
17
+ declare function getConfig(): TransactionalAuthConfig;
18
+ /**
19
+ * Check if the SDK is initialized.
20
+ */
21
+ declare function isInitialized(): boolean;
22
+
23
+ export { TransactionalAuthConfig, getConfig, initTransactionalAuth, isInitialized };