@artatol-acp/auth-nextjs 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 +214 -0
- package/dist/client/index.d.ts +17 -0
- package/dist/client/index.jsx +49 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/middleware.d.ts +7 -0
- package/dist/middleware.js +40 -0
- package/dist/server/index.d.ts +14 -0
- package/dist/server/index.js +107 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# @artatol-acp/auth-nextjs
|
|
2
|
+
|
|
3
|
+
Next.js SDK for Artatol Cloud Platform Authentication with support for App Router, Server Actions, and Middleware.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @artatol-acp/auth-nextjs
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @artatol-acp/auth-nextjs
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Setup
|
|
14
|
+
|
|
15
|
+
### 1. Initialize Server-side
|
|
16
|
+
|
|
17
|
+
Create `lib/auth.ts`:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { initACPAuth } from '@artatol-acp/auth-nextjs/server';
|
|
21
|
+
import { readFileSync } from 'fs';
|
|
22
|
+
|
|
23
|
+
const publicKey = readFileSync('./keys/public.pem', 'utf-8');
|
|
24
|
+
|
|
25
|
+
export const auth = initACPAuth({
|
|
26
|
+
baseUrl: process.env.ACP_AUTH_URL || 'https://sso.artatol.com',
|
|
27
|
+
jwtPublicKey: publicKey,
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 2. Add Middleware (Optional)
|
|
32
|
+
|
|
33
|
+
Create `middleware.ts`:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { createACPAuthMiddleware } from '@artatol-acp/auth-nextjs/middleware';
|
|
37
|
+
import { readFileSync } from 'fs';
|
|
38
|
+
|
|
39
|
+
const publicKey = readFileSync('./keys/public.pem', 'utf-8');
|
|
40
|
+
|
|
41
|
+
export const middleware = createACPAuthMiddleware({
|
|
42
|
+
jwtPublicKey: publicKey,
|
|
43
|
+
publicPaths: ['/login', '/register', '/forgot-password'],
|
|
44
|
+
loginPath: '/login',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export const config = {
|
|
48
|
+
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 3. Add Client Provider (Optional)
|
|
53
|
+
|
|
54
|
+
In your root layout (`app/layout.tsx`):
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { ACPAuthProvider } from '@artatol-acp/auth-nextjs/client';
|
|
58
|
+
|
|
59
|
+
export default function RootLayout({ children }) {
|
|
60
|
+
return (
|
|
61
|
+
<html>
|
|
62
|
+
<body>
|
|
63
|
+
<ACPAuthProvider baseUrl={process.env.NEXT_PUBLIC_ACP_AUTH_URL}>
|
|
64
|
+
{children}
|
|
65
|
+
</ACPAuthProvider>
|
|
66
|
+
</body>
|
|
67
|
+
</html>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Usage
|
|
73
|
+
|
|
74
|
+
### Server Components
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { getUser } from '@artatol-acp/auth-nextjs/server';
|
|
78
|
+
|
|
79
|
+
export default async function ProfilePage() {
|
|
80
|
+
const user = await getUser();
|
|
81
|
+
|
|
82
|
+
if (!user) {
|
|
83
|
+
return <div>Not logged in</div>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<div>
|
|
88
|
+
<h1>Welcome {user.email}</h1>
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Server Actions
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
'use server';
|
|
98
|
+
|
|
99
|
+
import { login, register, logout } from '@artatol-acp/auth-nextjs/server';
|
|
100
|
+
import { redirect } from 'next/navigation';
|
|
101
|
+
|
|
102
|
+
export async function loginAction(formData: FormData) {
|
|
103
|
+
const email = formData.get('email') as string;
|
|
104
|
+
const password = formData.get('password') as string;
|
|
105
|
+
|
|
106
|
+
const result = await login(email, password);
|
|
107
|
+
|
|
108
|
+
if ('requiresTwoFactor' in result) {
|
|
109
|
+
// Handle 2FA
|
|
110
|
+
return { requires2FA: true, tempToken: result.tempToken };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
redirect('/dashboard');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export async function registerAction(formData: FormData) {
|
|
117
|
+
const email = formData.get('email') as string;
|
|
118
|
+
const password = formData.get('password') as string;
|
|
119
|
+
|
|
120
|
+
await register(email, password);
|
|
121
|
+
redirect('/login');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function logoutAction() {
|
|
125
|
+
await logout();
|
|
126
|
+
redirect('/login');
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Client Components
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
'use client';
|
|
134
|
+
|
|
135
|
+
import { useAuth } from '@artatol-acp/auth-nextjs/client';
|
|
136
|
+
|
|
137
|
+
export function LoginForm() {
|
|
138
|
+
const { login, user, isLoading } = useAuth();
|
|
139
|
+
|
|
140
|
+
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
141
|
+
e.preventDefault();
|
|
142
|
+
const formData = new FormData(e.currentTarget);
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
await login(
|
|
146
|
+
formData.get('email') as string,
|
|
147
|
+
formData.get('password') as string
|
|
148
|
+
);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.error('Login failed:', error);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
if (isLoading) return <div>Loading...</div>;
|
|
155
|
+
if (user) return <div>Welcome {user.email}</div>;
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<form onSubmit={handleSubmit}>
|
|
159
|
+
<input name="email" type="email" required />
|
|
160
|
+
<input name="password" type="password" required />
|
|
161
|
+
<button type="submit">Login</button>
|
|
162
|
+
</form>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### API Routes
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { ACPAuthClient } from '@artatol-acp/auth-nextjs/server';
|
|
171
|
+
|
|
172
|
+
const client = new ACPAuthClient({
|
|
173
|
+
baseUrl: process.env.ACP_AUTH_URL!,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
export async function POST(request: Request) {
|
|
177
|
+
const { email, password } = await request.json();
|
|
178
|
+
|
|
179
|
+
const result = await client.login({ email, password });
|
|
180
|
+
|
|
181
|
+
return Response.json(result);
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Environment Variables
|
|
186
|
+
|
|
187
|
+
```env
|
|
188
|
+
ACP_AUTH_URL=https://sso.artatol.com
|
|
189
|
+
NEXT_PUBLIC_ACP_AUTH_URL=https://sso.artatol.com
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## API Reference
|
|
193
|
+
|
|
194
|
+
### Server Functions
|
|
195
|
+
|
|
196
|
+
- `initACPAuth(options)` - Initialize the auth client
|
|
197
|
+
- `getUser()` - Get current user from access token
|
|
198
|
+
- `verifyAccessToken(token)` - Verify and decode access token
|
|
199
|
+
- `refreshAccessToken()` - Refresh access token using refresh token cookie
|
|
200
|
+
- `login(email, password)` - Login user
|
|
201
|
+
- `logout()` - Logout user
|
|
202
|
+
- `register(email, password)` - Register new user
|
|
203
|
+
|
|
204
|
+
### Client Hooks
|
|
205
|
+
|
|
206
|
+
- `useAuth()` - Access auth context (user, isLoading, login, logout, refresh)
|
|
207
|
+
|
|
208
|
+
### Middleware
|
|
209
|
+
|
|
210
|
+
- `createACPAuthMiddleware(options)` - Create middleware for route protection
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { User } from '@artatol-acp/auth-js';
|
|
2
|
+
import { type ReactNode } from 'react';
|
|
3
|
+
export type ACPAuthContextValue = {
|
|
4
|
+
user: User | null;
|
|
5
|
+
isLoading: boolean;
|
|
6
|
+
login: (email: string, password: string) => Promise<void>;
|
|
7
|
+
logout: () => Promise<void>;
|
|
8
|
+
refresh: () => Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
export type ACPAuthProviderProps = {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
baseUrl: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function ACPAuthProvider({ children, baseUrl }: ACPAuthProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function useAuth(): ACPAuthContextValue;
|
|
16
|
+
export { ACPAuthClient } from '@artatol-acp/auth-js';
|
|
17
|
+
export type * from '@artatol-acp/auth-js';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** @jsxImportSource react */
|
|
2
|
+
'use client';
|
|
3
|
+
import { ACPAuthClient } from '@artatol-acp/auth-js';
|
|
4
|
+
import { createContext, useContext, useState, useEffect } from 'react';
|
|
5
|
+
const ACPAuthContext = createContext(null);
|
|
6
|
+
export function ACPAuthProvider({ children, baseUrl }) {
|
|
7
|
+
const [user, setUser] = useState(null);
|
|
8
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
9
|
+
const [client] = useState(() => new ACPAuthClient({ baseUrl }));
|
|
10
|
+
const refresh = async () => {
|
|
11
|
+
try {
|
|
12
|
+
await client.refresh();
|
|
13
|
+
// After refresh, we need to verify the new token
|
|
14
|
+
// This would require a server action or API route
|
|
15
|
+
// For now, we'll just mark as authenticated
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
setUser(null);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const login = async (email, password) => {
|
|
22
|
+
const result = await client.login({ email, password });
|
|
23
|
+
if ('requiresTwoFactor' in result) {
|
|
24
|
+
throw new Error('2FA_REQUIRED');
|
|
25
|
+
}
|
|
26
|
+
// User logged in successfully
|
|
27
|
+
setUser(result.user);
|
|
28
|
+
};
|
|
29
|
+
const logout = async () => {
|
|
30
|
+
await client.logout();
|
|
31
|
+
setUser(null);
|
|
32
|
+
};
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
// Try to restore session on mount
|
|
35
|
+
refresh().finally(() => setIsLoading(false));
|
|
36
|
+
}, []);
|
|
37
|
+
return (<ACPAuthContext.Provider value={{ user, isLoading, login, logout, refresh }}>
|
|
38
|
+
{children}
|
|
39
|
+
</ACPAuthContext.Provider>);
|
|
40
|
+
}
|
|
41
|
+
export function useAuth() {
|
|
42
|
+
const context = useContext(ACPAuthContext);
|
|
43
|
+
if (!context) {
|
|
44
|
+
throw new Error('useAuth must be used within ACPAuthProvider');
|
|
45
|
+
}
|
|
46
|
+
return context;
|
|
47
|
+
}
|
|
48
|
+
// Re-export client for direct use
|
|
49
|
+
export { ACPAuthClient } from '@artatol-acp/auth-js';
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
export type ACPAuthMiddlewareOptions = {
|
|
3
|
+
jwtPublicKey: string;
|
|
4
|
+
publicPaths?: string[];
|
|
5
|
+
loginPath?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function createACPAuthMiddleware(options: ACPAuthMiddlewareOptions): (request: NextRequest) => Promise<NextResponse<unknown>>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { jwtVerify, importSPKI } from 'jose';
|
|
3
|
+
let publicKey = null;
|
|
4
|
+
export function createACPAuthMiddleware(options) {
|
|
5
|
+
const { jwtPublicKey, publicPaths = ['/login', '/register', '/forgot-password', '/reset-password'], loginPath = '/login', } = options;
|
|
6
|
+
return async function acpAuthMiddleware(request) {
|
|
7
|
+
const { pathname } = request.nextUrl;
|
|
8
|
+
// Allow public paths
|
|
9
|
+
if (publicPaths.some(path => pathname.startsWith(path))) {
|
|
10
|
+
return NextResponse.next();
|
|
11
|
+
}
|
|
12
|
+
// Check for access token
|
|
13
|
+
const accessToken = request.cookies.get('access_token')?.value;
|
|
14
|
+
if (!accessToken) {
|
|
15
|
+
// Redirect to login
|
|
16
|
+
const url = request.nextUrl.clone();
|
|
17
|
+
url.pathname = loginPath;
|
|
18
|
+
url.searchParams.set('from', pathname);
|
|
19
|
+
return NextResponse.redirect(url);
|
|
20
|
+
}
|
|
21
|
+
// Verify access token
|
|
22
|
+
try {
|
|
23
|
+
if (!publicKey) {
|
|
24
|
+
publicKey = await importSPKI(jwtPublicKey, 'EdDSA');
|
|
25
|
+
}
|
|
26
|
+
await jwtVerify(accessToken, publicKey, {
|
|
27
|
+
algorithms: ['EdDSA'],
|
|
28
|
+
});
|
|
29
|
+
return NextResponse.next();
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
// Token invalid, try to refresh
|
|
33
|
+
// For now, redirect to login
|
|
34
|
+
const url = request.nextUrl.clone();
|
|
35
|
+
url.pathname = loginPath;
|
|
36
|
+
url.searchParams.set('from', pathname);
|
|
37
|
+
return NextResponse.redirect(url);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ACPAuthClient, type User, type LoginResult } from '@artatol-acp/auth-js';
|
|
2
|
+
export type ACPAuthServerOptions = {
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
jwtPublicKey: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function initACPAuth(options: ACPAuthServerOptions): ACPAuthClient;
|
|
7
|
+
export declare function verifyAccessToken(token: string): Promise<User>;
|
|
8
|
+
export declare function getUser(): Promise<User | null>;
|
|
9
|
+
export declare function refreshAccessToken(): Promise<string | null>;
|
|
10
|
+
export declare function login(email: string, password: string): Promise<LoginResult>;
|
|
11
|
+
export declare function logout(): Promise<void>;
|
|
12
|
+
export declare function register(email: string, password: string): Promise<User>;
|
|
13
|
+
export { ACPAuthClient } from '@artatol-acp/auth-js';
|
|
14
|
+
export type * from '@artatol-acp/auth-js';
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { cookies } from 'next/headers';
|
|
2
|
+
import { ACPAuthClient } from '@artatol-acp/auth-js';
|
|
3
|
+
import { jwtVerify, importSPKI } from 'jose';
|
|
4
|
+
let authClient = null;
|
|
5
|
+
let publicKey = null;
|
|
6
|
+
let config = null;
|
|
7
|
+
export function initACPAuth(options) {
|
|
8
|
+
config = options;
|
|
9
|
+
authClient = new ACPAuthClient({ baseUrl: options.baseUrl });
|
|
10
|
+
return authClient;
|
|
11
|
+
}
|
|
12
|
+
async function getPublicKey() {
|
|
13
|
+
if (!config) {
|
|
14
|
+
throw new Error('ACP Auth not initialized. Call initACPAuth() first.');
|
|
15
|
+
}
|
|
16
|
+
if (!publicKey) {
|
|
17
|
+
publicKey = await importSPKI(config.jwtPublicKey, 'EdDSA');
|
|
18
|
+
}
|
|
19
|
+
return publicKey;
|
|
20
|
+
}
|
|
21
|
+
function getClient() {
|
|
22
|
+
if (!authClient) {
|
|
23
|
+
throw new Error('ACP Auth not initialized. Call initACPAuth() first.');
|
|
24
|
+
}
|
|
25
|
+
return authClient;
|
|
26
|
+
}
|
|
27
|
+
export async function verifyAccessToken(token) {
|
|
28
|
+
const key = await getPublicKey();
|
|
29
|
+
try {
|
|
30
|
+
const { payload } = await jwtVerify(token, key, {
|
|
31
|
+
algorithms: ['EdDSA'],
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
id: payload.authUserId,
|
|
35
|
+
email: payload.email,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
throw new Error('Invalid access token');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export async function getUser() {
|
|
43
|
+
const cookieStore = await cookies();
|
|
44
|
+
const accessToken = cookieStore.get('access_token')?.value;
|
|
45
|
+
if (!accessToken) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
return await verifyAccessToken(accessToken);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export async function refreshAccessToken() {
|
|
56
|
+
const client = getClient();
|
|
57
|
+
try {
|
|
58
|
+
const { accessToken } = await client.refresh();
|
|
59
|
+
// Set new access token cookie
|
|
60
|
+
const cookieStore = await cookies();
|
|
61
|
+
cookieStore.set('access_token', accessToken, {
|
|
62
|
+
httpOnly: true,
|
|
63
|
+
secure: process.env.NODE_ENV === 'production',
|
|
64
|
+
sameSite: 'lax',
|
|
65
|
+
maxAge: 60 * 5, // 5 minutes
|
|
66
|
+
path: '/',
|
|
67
|
+
});
|
|
68
|
+
return accessToken;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export async function login(email, password) {
|
|
75
|
+
const client = getClient();
|
|
76
|
+
const result = await client.login({ email, password });
|
|
77
|
+
if ('accessToken' in result) {
|
|
78
|
+
// Set access token cookie
|
|
79
|
+
const cookieStore = await cookies();
|
|
80
|
+
cookieStore.set('access_token', result.accessToken, {
|
|
81
|
+
httpOnly: true,
|
|
82
|
+
secure: process.env.NODE_ENV === 'production',
|
|
83
|
+
sameSite: 'lax',
|
|
84
|
+
maxAge: 60 * 5, // 5 minutes
|
|
85
|
+
path: '/',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
export async function logout() {
|
|
91
|
+
const client = getClient();
|
|
92
|
+
try {
|
|
93
|
+
await client.logout();
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
// Clear cookies
|
|
97
|
+
const cookieStore = await cookies();
|
|
98
|
+
cookieStore.delete('access_token');
|
|
99
|
+
cookieStore.delete('refresh_token');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export async function register(email, password) {
|
|
103
|
+
const client = getClient();
|
|
104
|
+
return await client.register({ email, password });
|
|
105
|
+
}
|
|
106
|
+
// Re-export client for direct use if needed
|
|
107
|
+
export { ACPAuthClient } from '@artatol-acp/auth-js';
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@artatol-acp/auth-nextjs",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Next.js SDK for Artatol Cloud Platform Authentication",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./server": {
|
|
15
|
+
"import": "./dist/server/index.js",
|
|
16
|
+
"types": "./dist/server/index.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./client": {
|
|
19
|
+
"import": "./dist/client/index.js",
|
|
20
|
+
"types": "./dist/client/index.d.ts"
|
|
21
|
+
},
|
|
22
|
+
"./middleware": {
|
|
23
|
+
"import": "./dist/middleware.js",
|
|
24
|
+
"types": "./dist/middleware.d.ts"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"dev": "tsc --watch",
|
|
33
|
+
"typecheck": "tsc --noEmit"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"acp",
|
|
37
|
+
"auth",
|
|
38
|
+
"authentication",
|
|
39
|
+
"artatol",
|
|
40
|
+
"jwt",
|
|
41
|
+
"2fa",
|
|
42
|
+
"nextjs",
|
|
43
|
+
"next.js"
|
|
44
|
+
],
|
|
45
|
+
"author": "Artatol",
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@artatol-acp/auth-js": "workspace:*",
|
|
49
|
+
"jose": "^6.1.3"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"next": ">=15.0.0",
|
|
53
|
+
"react": ">=18.0.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/node": "^24.10.1",
|
|
57
|
+
"@types/react": "^18.3.18",
|
|
58
|
+
"next": "^15.1.6",
|
|
59
|
+
"react": "^18.3.1",
|
|
60
|
+
"typescript": "^5.7.2"
|
|
61
|
+
},
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"access": "public"
|
|
64
|
+
}
|
|
65
|
+
}
|