@authaz/next 0.0.1 → 1.0.1
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 +29 -174
- package/dist/index.d.ts +209 -11
- package/dist/index.js +434 -22
- package/package.json +66 -50
- package/CHANGELOG.md +0 -64
- package/CLAUDE.md +0 -118
- package/docs/ENVIRONMENT-CONFIG.md +0 -171
- package/docs/README-AXIOS-INSTANCE.md +0 -276
- package/docs/REFACTORING.md +0 -163
- package/docs/STATUS-CODES.md +0 -141
- package/jest.config.js +0 -25
- package/src/index.tsx +0 -34
- package/tsconfig.json +0 -12
- package/tsdown.config.ts +0 -21
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @authaz/next
|
|
2
2
|
|
|
3
|
-
Next.js
|
|
3
|
+
Next.js SDK for Authaz authentication.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -12,198 +12,53 @@ pnpm add @authaz/next @authaz/sdk
|
|
|
12
12
|
yarn add @authaz/next @authaz/sdk
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
## Usage
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
npm install next@">=15" react@">=17" @authaz/sdk@workspace:*
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Features
|
|
22
|
-
|
|
23
|
-
- **Server-Side Session Management** - Secure cookie-based authentication
|
|
24
|
-
- **Next.js 15+ Support** - Built for the latest Next.js features
|
|
25
|
-
- **Type-Safe** - Full TypeScript support
|
|
26
|
-
- **Cookie Integration** - Uses Next.js cookies API for secure token storage
|
|
27
|
-
- **Debug Mode** - Optional debug logging for development
|
|
28
|
-
- **Zero Configuration** - Works with sensible defaults
|
|
29
|
-
|
|
30
|
-
## Quick Start
|
|
31
|
-
|
|
32
|
-
### 1. Configure Authaz SDK
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
// lib/authaz.ts
|
|
36
|
-
import { authazNext } from "@authaz/next";
|
|
37
|
-
|
|
38
|
-
export const authaz = authazNext(
|
|
39
|
-
{
|
|
40
|
-
clientId: process.env.AUTHAZ_CLIENT_ID!,
|
|
41
|
-
clientSecret: process.env.AUTHAZ_CLIENT_SECRET!,
|
|
42
|
-
tenantId: process.env.AUTHAZ_TENANT_ID!,
|
|
43
|
-
organizationId: process.env.AUTHAZ_ORG_ID!,
|
|
44
|
-
redirectUri: process.env.AUTHAZ_REDIRECT_URI!,
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
debug: process.env.NODE_ENV === "development",
|
|
48
|
-
cookies: {
|
|
49
|
-
accessToken: "accessToken", // optional
|
|
50
|
-
},
|
|
51
|
-
}
|
|
52
|
-
);
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### 2. Use in Server Components
|
|
56
|
-
|
|
57
|
-
```tsx
|
|
58
|
-
// app/dashboard/page.tsx
|
|
59
|
-
import { authaz } from "@/lib/authaz";
|
|
60
|
-
import { redirect } from "next/navigation";
|
|
61
|
-
|
|
62
|
-
export default async function DashboardPage() {
|
|
63
|
-
const user = await authaz.getUserSession();
|
|
64
|
-
|
|
65
|
-
if (!user) {
|
|
66
|
-
redirect("/login");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return (
|
|
70
|
-
<div>
|
|
71
|
-
<h1>Welcome, {user.name}</h1>
|
|
72
|
-
<p>Email: {user.email}</p>
|
|
73
|
-
</div>
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### 3. Use in API Routes
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
// app/api/user/route.ts
|
|
82
|
-
import { authaz } from "@/lib/authaz";
|
|
83
|
-
import { NextResponse } from "next/server";
|
|
84
|
-
|
|
85
|
-
export async function GET() {
|
|
86
|
-
const user = await authaz.getUserSession();
|
|
87
|
-
|
|
88
|
-
if (!user) {
|
|
89
|
-
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return NextResponse.json({ user });
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## API Reference
|
|
97
|
-
|
|
98
|
-
### `authazNext(config, options?)`
|
|
99
|
-
|
|
100
|
-
Creates an Authaz instance configured for Next.js.
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
// SDK Configuration (required)
|
|
104
|
-
config: {
|
|
105
|
-
clientId: string;
|
|
106
|
-
clientSecret: string;
|
|
107
|
-
tenantId: string;
|
|
108
|
-
organizationId: string;
|
|
109
|
-
redirectUri?: string;
|
|
110
|
-
authPoolId?: string;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// SDK Options (optional)
|
|
114
|
-
options?: {
|
|
115
|
-
debug?: boolean;
|
|
116
|
-
cookies?: {
|
|
117
|
-
accessToken?: string; // Default: "accessToken"
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
Returns:
|
|
17
|
+
### API Routes Setup
|
|
123
18
|
|
|
124
19
|
```typescript
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### `getUserSession()`
|
|
20
|
+
// app/api/auth/[...authaz]/route.ts
|
|
21
|
+
import { createAuthazHandler } from '@authaz/next';
|
|
131
22
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
```typescript
|
|
137
|
-
interface UserProfile {
|
|
138
|
-
id: string;
|
|
139
|
-
email: string;
|
|
140
|
-
name: string;
|
|
141
|
-
role?: string;
|
|
142
|
-
createdAt?: string;
|
|
143
|
-
updatedAt?: string;
|
|
144
|
-
}
|
|
23
|
+
export const { GET, POST } = createAuthazHandler({
|
|
24
|
+
clientId: process.env.AUTHAZ_CLIENT_ID!,
|
|
25
|
+
clientSecret: process.env.AUTHAZ_CLIENT_SECRET!,
|
|
26
|
+
});
|
|
145
27
|
```
|
|
146
28
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
Create a `.env.local` file:
|
|
150
|
-
|
|
151
|
-
```env
|
|
152
|
-
AUTHAZ_CLIENT_ID=your_client_id
|
|
153
|
-
AUTHAZ_CLIENT_SECRET=your_client_secret
|
|
154
|
-
AUTHAZ_TENANT_ID=your_tenant_id
|
|
155
|
-
AUTHAZ_ORG_ID=your_organization_id
|
|
156
|
-
AUTHAZ_REDIRECT_URI=http://localhost:3000/callback
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## Middleware Protection
|
|
160
|
-
|
|
161
|
-
Protect multiple routes with Next.js middleware:
|
|
29
|
+
### Middleware
|
|
162
30
|
|
|
163
31
|
```typescript
|
|
164
32
|
// middleware.ts
|
|
165
|
-
import {
|
|
166
|
-
import type { NextRequest } from "next/server";
|
|
167
|
-
import { authaz } from "@/lib/authaz";
|
|
33
|
+
import { withAuthaz } from '@authaz/next';
|
|
168
34
|
|
|
169
|
-
export
|
|
170
|
-
const user = await authaz.getUserSession();
|
|
171
|
-
|
|
172
|
-
if (request.nextUrl.pathname.startsWith("/dashboard") && !user) {
|
|
173
|
-
return NextResponse.redirect(new URL("/login", request.url));
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return NextResponse.next();
|
|
177
|
-
}
|
|
35
|
+
export default withAuthaz();
|
|
178
36
|
|
|
179
37
|
export const config = {
|
|
180
|
-
|
|
38
|
+
matcher: ['/dashboard/:path*', '/api/:path*'],
|
|
181
39
|
};
|
|
182
40
|
```
|
|
183
41
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
1. **Use HTTP-Only Cookies** - Always set `httpOnly: true`
|
|
187
|
-
2. **Enable Secure Flag in Production** - Set `secure: true` when `NODE_ENV === "production"`
|
|
188
|
-
3. **Set SameSite** - Use `sameSite: "lax"` or `"strict"`
|
|
189
|
-
4. **Never Expose Client Secret** - Only use this package in server-side code
|
|
190
|
-
5. **Implement Token Refresh** - Refresh tokens before expiration
|
|
191
|
-
|
|
192
|
-
## TypeScript Support
|
|
193
|
-
|
|
194
|
-
Full TypeScript support with type inference:
|
|
42
|
+
### Server Components
|
|
195
43
|
|
|
196
44
|
```typescript
|
|
197
|
-
import
|
|
198
|
-
|
|
199
|
-
|
|
45
|
+
import { getSession } from '@authaz/next';
|
|
46
|
+
|
|
47
|
+
async function Page() {
|
|
48
|
+
const session = await getSession();
|
|
49
|
+
|
|
50
|
+
if (!session) {
|
|
51
|
+
return <div>Not authenticated</div>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return <div>Hello, {session.user?.name}</div>;
|
|
55
|
+
}
|
|
200
56
|
```
|
|
201
57
|
|
|
202
|
-
##
|
|
58
|
+
## Documentation
|
|
203
59
|
|
|
204
|
-
|
|
60
|
+
For full documentation, visit [https://authaz.io/docs](https://authaz.io/docs)
|
|
205
61
|
|
|
206
|
-
##
|
|
62
|
+
## License
|
|
207
63
|
|
|
208
|
-
|
|
209
|
-
- Documentation: https://www.authaz.io/docs
|
|
64
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,215 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { AuthazClient, AuthazConfig, AuthazError, AuthazUser, LoginResult, TokenSet } from "@authaz/sdk";
|
|
2
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
3
3
|
|
|
4
4
|
//#region src/index.d.ts
|
|
5
|
-
type
|
|
5
|
+
type AuthazNextConfig = AuthazConfig & {
|
|
6
|
+
/**
|
|
7
|
+
* Base path for auth routes (default: "/api/auth")
|
|
8
|
+
* Routes will be: {basePath}/login, {basePath}/callback, {basePath}/logout
|
|
9
|
+
*/
|
|
10
|
+
basePath?: string;
|
|
11
|
+
/**
|
|
12
|
+
* URL to redirect to after successful login (default: "/")
|
|
13
|
+
*/
|
|
14
|
+
afterLoginUrl?: string;
|
|
15
|
+
/**
|
|
16
|
+
* URL to redirect to after logout (default: "/")
|
|
17
|
+
*/
|
|
18
|
+
afterLogoutUrl?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Fixed redirect URI for OAuth callback.
|
|
21
|
+
* This should match exactly what's registered in the Identity Provider.
|
|
22
|
+
* Example: "https://dashboard:3000/auth/redirect"
|
|
23
|
+
* If not provided, the SDK will construct it from the request URL.
|
|
24
|
+
*/
|
|
25
|
+
redirectUri?: string;
|
|
26
|
+
/**
|
|
27
|
+
* API key for API requests (X-API-Key header).
|
|
28
|
+
* Falls back to clientSecret if not provided.
|
|
29
|
+
*/
|
|
30
|
+
apiKey?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Enable debug logging
|
|
33
|
+
*/
|
|
6
34
|
debug?: boolean;
|
|
7
|
-
cookies?: {
|
|
8
|
-
accessToken?: string;
|
|
9
|
-
};
|
|
10
35
|
};
|
|
11
|
-
type
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
36
|
+
type AuthHandler = {
|
|
37
|
+
GET: (request: NextRequest) => Promise<NextResponse>;
|
|
38
|
+
POST: (request: NextRequest) => Promise<NextResponse>;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Creates the Authaz Next.js authentication handler.
|
|
42
|
+
*
|
|
43
|
+
* This creates a route handler that manages the complete OAuth flow:
|
|
44
|
+
* - GET /api/auth/login - Redirects to Universal Login
|
|
45
|
+
* - POST /api/auth/callback - Handles OAuth callback (receives code via form POST)
|
|
46
|
+
* - POST /api/auth/logout - Clears session and redirects to logout (POST-only for CSRF protection)
|
|
47
|
+
* - GET /api/auth/me - Returns current user info (requires valid session)
|
|
48
|
+
* - POST /api/auth/refresh - Refreshes the access token
|
|
49
|
+
*
|
|
50
|
+
* IMPORTANT: The OAuth callback from the identity provider arrives as GET.
|
|
51
|
+
* You need a callback page that POSTs to /api/auth/callback:
|
|
52
|
+
*
|
|
53
|
+
* ```tsx
|
|
54
|
+
* // app/auth/callback/page.tsx
|
|
55
|
+
* 'use client';
|
|
56
|
+
* import { useEffect } from 'react';
|
|
57
|
+
* import { useSearchParams } from 'next/navigation';
|
|
58
|
+
*
|
|
59
|
+
* export default function CallbackPage() {
|
|
60
|
+
* const searchParams = useSearchParams();
|
|
61
|
+
*
|
|
62
|
+
* useEffect(() => {
|
|
63
|
+
* const form = document.createElement('form');
|
|
64
|
+
* form.method = 'POST';
|
|
65
|
+
* form.action = '/api/auth/callback';
|
|
66
|
+
*
|
|
67
|
+
* const code = searchParams.get('code');
|
|
68
|
+
* const state = searchParams.get('state');
|
|
69
|
+
* const error = searchParams.get('error');
|
|
70
|
+
*
|
|
71
|
+
* ['code', 'state', 'error', 'error_description'].forEach(param => {
|
|
72
|
+
* const value = searchParams.get(param);
|
|
73
|
+
* if (value) {
|
|
74
|
+
* const input = document.createElement('input');
|
|
75
|
+
* input.type = 'hidden';
|
|
76
|
+
* input.name = param;
|
|
77
|
+
* input.value = value;
|
|
78
|
+
* form.appendChild(input);
|
|
79
|
+
* }
|
|
80
|
+
* });
|
|
81
|
+
*
|
|
82
|
+
* document.body.appendChild(form);
|
|
83
|
+
* form.submit();
|
|
84
|
+
* }, [searchParams]);
|
|
85
|
+
*
|
|
86
|
+
* return <div>Completing login...</div>;
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* // app/api/auth/[...authaz]/route.ts
|
|
93
|
+
* import { createAuthazHandler } from '@authaz/next';
|
|
94
|
+
*
|
|
95
|
+
* export const { GET, POST } = createAuthazHandler({
|
|
96
|
+
* clientId: process.env.AUTHAZ_CLIENT_ID!,
|
|
97
|
+
* clientSecret: process.env.AUTHAZ_CLIENT_SECRET!,
|
|
98
|
+
* tenantId: process.env.AUTHAZ_TENANT_ID!,
|
|
99
|
+
* organizationId: process.env.AUTHAZ_ORGANIZATION_ID!,
|
|
100
|
+
* });
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
declare const createAuthazHandler: (config: AuthazNextConfig) => AuthHandler;
|
|
104
|
+
/**
|
|
105
|
+
* Gets the current access token from cookies.
|
|
106
|
+
*/
|
|
107
|
+
declare const getAccessToken: () => Promise<string | null>;
|
|
108
|
+
/**
|
|
109
|
+
* Gets the current refresh token from cookies.
|
|
110
|
+
*/
|
|
111
|
+
declare const getRefreshToken: () => Promise<string | null>;
|
|
112
|
+
/**
|
|
113
|
+
* Checks if the user is authenticated (has an access token).
|
|
114
|
+
*/
|
|
115
|
+
declare const isAuthenticated: () => Promise<boolean>;
|
|
116
|
+
/**
|
|
117
|
+
* Creates helper functions that require the authazDomain for API calls.
|
|
118
|
+
*/
|
|
119
|
+
declare const createAuthazHelpers: (config: {
|
|
120
|
+
authazDomain?: string;
|
|
121
|
+
clientSecret?: string;
|
|
122
|
+
apiKey?: string;
|
|
123
|
+
}) => {
|
|
124
|
+
getUser: () => Promise<AuthazUser | null>;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Creates middleware config for protecting routes in Next.js middleware.ts
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```typescript
|
|
131
|
+
* // middleware.ts
|
|
132
|
+
* import { createAuthMiddleware } from '@authaz/next';
|
|
133
|
+
*
|
|
134
|
+
* export const middleware = createAuthMiddleware({
|
|
135
|
+
* publicPaths: ['/', '/login', '/api/auth'],
|
|
136
|
+
* loginPath: '/api/auth/login',
|
|
137
|
+
* });
|
|
138
|
+
*
|
|
139
|
+
* export const config = {
|
|
140
|
+
* matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
|
|
141
|
+
* };
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
declare const createAuthMiddleware: (options: {
|
|
145
|
+
/**
|
|
146
|
+
* Paths that don't require authentication (supports wildcards with *)
|
|
147
|
+
*/
|
|
148
|
+
publicPaths?: string[];
|
|
149
|
+
/**
|
|
150
|
+
* Path to redirect unauthenticated users to (default: '/api/auth/login')
|
|
151
|
+
*/
|
|
152
|
+
loginPath?: string;
|
|
153
|
+
}) => (request: NextRequest) => Promise<NextResponse>;
|
|
154
|
+
/**
|
|
155
|
+
* Wrapper for API route handlers that require authentication.
|
|
156
|
+
* Returns 401 if not authenticated.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* // app/api/protected/route.ts
|
|
161
|
+
* import { withAuth } from '@authaz/next';
|
|
162
|
+
*
|
|
163
|
+
* export const GET = withAuth(async (request) => {
|
|
164
|
+
* // User is authenticated
|
|
165
|
+
* return Response.json({ message: 'Protected data' });
|
|
166
|
+
* });
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
declare const withAuth: (handler: (request: NextRequest) => Promise<Response>) => ((request: NextRequest) => Promise<Response>);
|
|
170
|
+
/**
|
|
171
|
+
* Server Component helper that throws redirect if not authenticated.
|
|
172
|
+
* Use in Server Components to protect pages.
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* // app/dashboard/page.tsx
|
|
177
|
+
* import { requireAuth } from '@authaz/next';
|
|
178
|
+
*
|
|
179
|
+
* export default async function DashboardPage() {
|
|
180
|
+
* await requireAuth(); // Redirects to login if not authenticated
|
|
181
|
+
*
|
|
182
|
+
* return <div>Dashboard</div>;
|
|
183
|
+
* }
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
declare const requireAuth: (loginPath?: string) => Promise<void>;
|
|
187
|
+
/**
|
|
188
|
+
* Server Component helper that returns user or redirects if not authenticated.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```typescript
|
|
192
|
+
* // app/profile/page.tsx
|
|
193
|
+
* import { requireUser } from '@authaz/next';
|
|
194
|
+
*
|
|
195
|
+
* const helpers = requireUser({
|
|
196
|
+
* authazDomain: 'https://authaz.com',
|
|
197
|
+
* apiKey: process.env.AUTHAZ_API_KEY!,
|
|
198
|
+
* });
|
|
199
|
+
*
|
|
200
|
+
* export default async function ProfilePage() {
|
|
201
|
+
* const user = await helpers.getOrRedirect();
|
|
202
|
+
* return <div>Hello {user.name}</div>;
|
|
203
|
+
* }
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
declare const requireUser: (config: {
|
|
207
|
+
authazDomain?: string;
|
|
208
|
+
clientSecret?: string;
|
|
209
|
+
apiKey?: string;
|
|
210
|
+
loginPath?: string;
|
|
211
|
+
}) => {
|
|
212
|
+
getOrRedirect: () => Promise<AuthazUser>;
|
|
15
213
|
};
|
|
16
214
|
//#endregion
|
|
17
|
-
export {
|
|
215
|
+
export { type AuthazClient, type AuthazConfig, AuthazError, AuthazNextConfig, type AuthazUser, type LoginResult, type TokenSet, createAuthMiddleware, createAuthazHandler, createAuthazHelpers, getAccessToken, getRefreshToken, isAuthenticated, requireAuth, requireUser, withAuth };
|