hightjs 0.1.1 → 0.2.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 +147 -9
- package/dist/api/http.js +5 -3
- package/dist/auth/client.d.ts +11 -1
- package/dist/auth/client.js +78 -0
- package/dist/auth/core.d.ts +21 -4
- package/dist/auth/core.js +66 -17
- package/dist/auth/example.d.ts +40 -0
- package/dist/auth/example.js +104 -0
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.js +2 -1
- package/dist/auth/providers/credentials.d.ts +68 -0
- package/dist/auth/providers/credentials.js +132 -0
- package/dist/auth/providers/discord.d.ts +67 -0
- package/dist/auth/providers/discord.js +198 -0
- package/dist/auth/providers/index.d.ts +2 -0
- package/dist/auth/providers/index.js +19 -0
- package/dist/auth/providers.d.ts +2 -5
- package/dist/auth/providers.js +6 -12
- package/dist/auth/react.js +20 -13
- package/dist/auth/routes.d.ts +2 -2
- package/dist/auth/routes.js +45 -13
- package/dist/auth/types.d.ts +36 -21
- package/dist/router.js +9 -1
- package/package.json +1 -1
- package/src/api/http.ts +6 -2
- package/src/auth/client.ts +84 -3
- package/src/auth/core.ts +75 -19
- package/src/auth/example.ts +115 -0
- package/src/auth/index.ts +2 -1
- package/src/auth/providers/credentials.ts +158 -0
- package/src/auth/providers/discord.ts +231 -0
- package/src/auth/providers/index.ts +4 -0
- package/src/auth/providers.ts +3 -12
- package/src/auth/react.tsx +21 -13
- package/src/auth/routes.ts +51 -18
- package/src/auth/types.ts +49 -26
- package/src/router.ts +9 -1
package/dist/auth/routes.js
CHANGED
|
@@ -13,17 +13,31 @@ function createAuthRoutes(config) {
|
|
|
13
13
|
* Uso: /api/auth/[...value].ts
|
|
14
14
|
*/
|
|
15
15
|
return {
|
|
16
|
-
pattern: '/api/auth/[value]',
|
|
16
|
+
pattern: '/api/auth/[...value]',
|
|
17
17
|
async GET(req, params) {
|
|
18
18
|
const path = params["value"];
|
|
19
19
|
const route = Array.isArray(path) ? path.join('/') : path || '';
|
|
20
|
+
// Verifica rotas adicionais dos providers primeiro
|
|
21
|
+
const additionalRoutes = auth.getAllAdditionalRoutes();
|
|
22
|
+
for (const { provider, route: additionalRoute } of additionalRoutes) {
|
|
23
|
+
if (additionalRoute.method === 'GET' && additionalRoute.path.includes(route)) {
|
|
24
|
+
try {
|
|
25
|
+
return await additionalRoute.handler(req, params);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.error(`[${provider} Provider] Error in additional route:`, error);
|
|
29
|
+
return http_1.HightJSResponse.json({ error: 'Provider route error' }, { status: 500 });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Rotas padrão do sistema
|
|
20
34
|
switch (route) {
|
|
21
35
|
case 'session':
|
|
22
36
|
return await handleSession(req, auth);
|
|
23
37
|
case 'csrf':
|
|
24
38
|
return await handleCsrf(req);
|
|
25
39
|
case 'providers':
|
|
26
|
-
return await handleProviders(
|
|
40
|
+
return await handleProviders(auth);
|
|
27
41
|
default:
|
|
28
42
|
return http_1.HightJSResponse.json({ error: 'Route not found' }, { status: 404 });
|
|
29
43
|
}
|
|
@@ -31,6 +45,20 @@ function createAuthRoutes(config) {
|
|
|
31
45
|
async POST(req, params) {
|
|
32
46
|
const path = params["value"];
|
|
33
47
|
const route = Array.isArray(path) ? path.join('/') : path || '';
|
|
48
|
+
// Verifica rotas adicionais dos providers primeiro
|
|
49
|
+
const additionalRoutes = auth.getAllAdditionalRoutes();
|
|
50
|
+
for (const { provider, route: additionalRoute } of additionalRoutes) {
|
|
51
|
+
if (additionalRoute.method === 'POST' && additionalRoute.path.includes(route)) {
|
|
52
|
+
try {
|
|
53
|
+
return await additionalRoute.handler(req, params);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.error(`[${provider} Provider] Error in additional route:`, error);
|
|
57
|
+
return http_1.HightJSResponse.json({ error: 'Provider route error' }, { status: 500 });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Rotas padrão do sistema
|
|
34
62
|
switch (route) {
|
|
35
63
|
case 'signin':
|
|
36
64
|
return await handleSignIn(req, auth);
|
|
@@ -66,14 +94,8 @@ async function handleCsrf(req) {
|
|
|
66
94
|
/**
|
|
67
95
|
* Handler para GET /api/auth/providers
|
|
68
96
|
*/
|
|
69
|
-
async function handleProviders(
|
|
70
|
-
const providers =
|
|
71
|
-
.filter(p => p.type === 'credentials') // Apenas credentials
|
|
72
|
-
.map(p => ({
|
|
73
|
-
id: p.id,
|
|
74
|
-
name: p.name,
|
|
75
|
-
type: p.type
|
|
76
|
-
}));
|
|
97
|
+
async function handleProviders(auth) {
|
|
98
|
+
const providers = auth.getProviders();
|
|
77
99
|
return http_1.HightJSResponse.json({ providers });
|
|
78
100
|
}
|
|
79
101
|
/**
|
|
@@ -82,17 +104,27 @@ async function handleProviders(config) {
|
|
|
82
104
|
async function handleSignIn(req, auth) {
|
|
83
105
|
try {
|
|
84
106
|
const { provider = 'credentials', ...credentials } = await req.json();
|
|
85
|
-
// Apenas credentials agora
|
|
86
107
|
const result = await auth.signIn(provider, credentials);
|
|
87
108
|
if (!result) {
|
|
88
109
|
return http_1.HightJSResponse.json({ error: 'Invalid credentials' }, { status: 401 });
|
|
89
110
|
}
|
|
111
|
+
// Se tem redirectUrl, é OAuth - retorna URL para redirecionamento
|
|
112
|
+
if ('redirectUrl' in result) {
|
|
113
|
+
return http_1.HightJSResponse.json({
|
|
114
|
+
success: true,
|
|
115
|
+
redirectUrl: result.redirectUrl,
|
|
116
|
+
type: 'oauth'
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
// Se tem session, é credentials - retorna sessão
|
|
90
120
|
return auth.createAuthResponse(result.token, {
|
|
91
121
|
success: true,
|
|
92
|
-
user: result.session.user
|
|
122
|
+
user: result.session.user,
|
|
123
|
+
type: 'session'
|
|
93
124
|
});
|
|
94
125
|
}
|
|
95
126
|
catch (error) {
|
|
127
|
+
console.error('[hweb-auth] Erro no handleSignIn:', error);
|
|
96
128
|
return http_1.HightJSResponse.json({ error: 'Authentication failed' }, { status: 500 });
|
|
97
129
|
}
|
|
98
130
|
}
|
|
@@ -100,5 +132,5 @@ async function handleSignIn(req, auth) {
|
|
|
100
132
|
* Handler para POST /api/auth/signout
|
|
101
133
|
*/
|
|
102
134
|
async function handleSignOut(req, auth) {
|
|
103
|
-
return auth.signOut();
|
|
135
|
+
return await auth.signOut(req);
|
|
104
136
|
}
|
package/dist/auth/types.d.ts
CHANGED
|
@@ -4,8 +4,43 @@ export interface Session {
|
|
|
4
4
|
expires: string;
|
|
5
5
|
accessToken?: string;
|
|
6
6
|
}
|
|
7
|
+
export interface SignInOptions {
|
|
8
|
+
redirect?: boolean;
|
|
9
|
+
callbackUrl?: string;
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
}
|
|
12
|
+
export interface SignInResult {
|
|
13
|
+
error?: string;
|
|
14
|
+
status?: number;
|
|
15
|
+
ok?: boolean;
|
|
16
|
+
url?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface SessionContextType {
|
|
19
|
+
data: Session | null;
|
|
20
|
+
status: 'loading' | 'authenticated' | 'unauthenticated';
|
|
21
|
+
signIn: (provider?: string, options?: SignInOptions) => Promise<SignInResult | undefined>;
|
|
22
|
+
signOut: (options?: {
|
|
23
|
+
callbackUrl?: string;
|
|
24
|
+
}) => Promise<void>;
|
|
25
|
+
update: () => Promise<Session | null>;
|
|
26
|
+
}
|
|
27
|
+
export interface AuthRoute {
|
|
28
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
29
|
+
path: string;
|
|
30
|
+
handler: (req: any, params: any) => Promise<any>;
|
|
31
|
+
}
|
|
32
|
+
export interface AuthProviderClass {
|
|
33
|
+
id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
type: string;
|
|
36
|
+
handleOauth?(credentials: Record<string, string>): Promise<string> | string;
|
|
37
|
+
handleSignIn(credentials: Record<string, string>): Promise<User | string | null>;
|
|
38
|
+
handleSignOut?(): Promise<void>;
|
|
39
|
+
additionalRoutes?: AuthRoute[];
|
|
40
|
+
getConfig?(): any;
|
|
41
|
+
}
|
|
7
42
|
export interface AuthConfig {
|
|
8
|
-
providers:
|
|
43
|
+
providers: AuthProviderClass[];
|
|
9
44
|
pages?: {
|
|
10
45
|
signIn?: string;
|
|
11
46
|
signOut?: string;
|
|
@@ -30,26 +65,6 @@ export interface AuthProvider {
|
|
|
30
65
|
type: 'credentials';
|
|
31
66
|
authorize?: (credentials: Record<string, string>) => Promise<User | null> | User | null;
|
|
32
67
|
}
|
|
33
|
-
export interface SignInOptions {
|
|
34
|
-
redirect?: boolean;
|
|
35
|
-
callbackUrl?: string;
|
|
36
|
-
[key: string]: any;
|
|
37
|
-
}
|
|
38
|
-
export interface SignInResult {
|
|
39
|
-
error?: string;
|
|
40
|
-
status?: number;
|
|
41
|
-
ok?: boolean;
|
|
42
|
-
url?: string;
|
|
43
|
-
}
|
|
44
|
-
export interface SessionContextType {
|
|
45
|
-
data: Session | null;
|
|
46
|
-
status: 'loading' | 'authenticated' | 'unauthenticated';
|
|
47
|
-
signIn: (provider?: string, options?: SignInOptions) => Promise<SignInResult | undefined>;
|
|
48
|
-
signOut: (options?: {
|
|
49
|
-
callbackUrl?: string;
|
|
50
|
-
}) => Promise<void>;
|
|
51
|
-
update: () => Promise<Session | null>;
|
|
52
|
-
}
|
|
53
68
|
export interface CredentialsConfig {
|
|
54
69
|
id?: string;
|
|
55
70
|
name?: string;
|
package/dist/router.js
CHANGED
|
@@ -309,7 +309,15 @@ function findMatchingBackendRoute(pathname, method) {
|
|
|
309
309
|
// Verifica se a rota tem um handler para o método HTTP atual
|
|
310
310
|
if (!route.pattern || !route[method.toUpperCase()])
|
|
311
311
|
continue;
|
|
312
|
-
const regexPattern = route.pattern
|
|
312
|
+
const regexPattern = route.pattern
|
|
313
|
+
// [[...param]] → opcional catch-all
|
|
314
|
+
.replace(/\[\[\.\.\.(\w+)\]\]/g, '(?<$1>.+)?')
|
|
315
|
+
// [...param] → obrigatório catch-all
|
|
316
|
+
.replace(/\[\.\.\.(\w+)\]/g, '(?<$1>.+)')
|
|
317
|
+
// [[param]] → segmento opcional
|
|
318
|
+
.replace(/\[\[(\w+)\]\]/g, '(?<$1>[^/]+)?')
|
|
319
|
+
// [param] → segmento obrigatório
|
|
320
|
+
.replace(/\[(\w+)\]/g, '(?<$1>[^/]+)');
|
|
313
321
|
const regex = new RegExp(`^${regexPattern}/?$`);
|
|
314
322
|
const match = pathname.match(regex);
|
|
315
323
|
if (match) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hightjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "HightJS is a high-level framework for building web applications with ease and speed. It provides a robust set of tools and features to streamline development and enhance productivity.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
package/src/api/http.ts
CHANGED
|
@@ -407,12 +407,16 @@ export class HightJSResponse {
|
|
|
407
407
|
}
|
|
408
408
|
});
|
|
409
409
|
|
|
410
|
+
// Handle redirects specifically
|
|
411
|
+
if (this._headers['Location']) {
|
|
412
|
+
res.redirect(this._headers['Location']);
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
410
416
|
// Envia o corpo se foi definido
|
|
411
417
|
if (this._sent && this._body !== null) {
|
|
412
418
|
if (this._headers['Content-Type']?.includes('application/json')) {
|
|
413
419
|
res.json(JSON.parse(this._body));
|
|
414
|
-
} else if (this._headers['Location']) {
|
|
415
|
-
res.redirect(this._headers['Location']);
|
|
416
420
|
} else {
|
|
417
421
|
res.send(this._body);
|
|
418
422
|
}
|
package/src/auth/client.ts
CHANGED
|
@@ -6,9 +6,6 @@ export function setBasePath(path: string) {
|
|
|
6
6
|
basePath = path;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
9
|
/**
|
|
13
10
|
* Função para obter a sessão atual (similar ao NextAuth getSession)
|
|
14
11
|
*/
|
|
@@ -72,3 +69,87 @@ export async function getProviders(): Promise<any[] | null> {
|
|
|
72
69
|
}
|
|
73
70
|
}
|
|
74
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Função para fazer login (similar ao NextAuth signIn)
|
|
74
|
+
*/
|
|
75
|
+
export async function signIn(
|
|
76
|
+
provider: string = 'credentials',
|
|
77
|
+
options: SignInOptions = {}
|
|
78
|
+
): Promise<SignInResult | undefined> {
|
|
79
|
+
try {
|
|
80
|
+
const { redirect = true, callbackUrl, ...credentials } = options;
|
|
81
|
+
|
|
82
|
+
const response = await fetch(`${basePath}/signin`, {
|
|
83
|
+
method: 'POST',
|
|
84
|
+
headers: {
|
|
85
|
+
'Content-Type': 'application/json',
|
|
86
|
+
},
|
|
87
|
+
credentials: 'include',
|
|
88
|
+
body: JSON.stringify({
|
|
89
|
+
provider,
|
|
90
|
+
...credentials
|
|
91
|
+
})
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const data = await response.json();
|
|
95
|
+
|
|
96
|
+
if (response.ok && data.success) {
|
|
97
|
+
// Se é OAuth, redireciona para URL fornecida
|
|
98
|
+
if (data.type === 'oauth' && data.redirectUrl) {
|
|
99
|
+
if (redirect && typeof window !== 'undefined') {
|
|
100
|
+
window.location.href = data.redirectUrl;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
ok: true,
|
|
105
|
+
status: 200,
|
|
106
|
+
url: data.redirectUrl
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Se é sessão (credentials), redireciona para callbackUrl
|
|
111
|
+
if (data.type === 'session') {
|
|
112
|
+
if (redirect && typeof window !== 'undefined') {
|
|
113
|
+
window.location.href = callbackUrl || '/';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
ok: true,
|
|
118
|
+
status: 200,
|
|
119
|
+
url: callbackUrl || '/'
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
return {
|
|
124
|
+
error: data.error || 'Authentication failed',
|
|
125
|
+
status: response.status,
|
|
126
|
+
ok: false
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error('[hweb-auth] Erro no signIn:', error);
|
|
131
|
+
return {
|
|
132
|
+
error: 'Network error',
|
|
133
|
+
status: 500,
|
|
134
|
+
ok: false
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Função para fazer logout (similar ao NextAuth signOut)
|
|
141
|
+
*/
|
|
142
|
+
export async function signOut(options: { callbackUrl?: string } = {}): Promise<void> {
|
|
143
|
+
try {
|
|
144
|
+
await fetch(`${basePath}/signout`, {
|
|
145
|
+
method: 'POST',
|
|
146
|
+
credentials: 'include'
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
if (typeof window !== 'undefined') {
|
|
150
|
+
window.location.href = options.callbackUrl || '/';
|
|
151
|
+
}
|
|
152
|
+
} catch (error) {
|
|
153
|
+
console.error('[hweb-auth] Erro no signOut:', error);
|
|
154
|
+
}
|
|
155
|
+
}
|
package/src/auth/core.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HightJSRequest, HightJSResponse } from '../api/http';
|
|
2
|
-
import type { AuthConfig,
|
|
2
|
+
import type { AuthConfig, AuthProviderClass, User, Session } from './types';
|
|
3
3
|
import { SessionManager } from './jwt';
|
|
4
4
|
|
|
5
5
|
export class HWebAuth {
|
|
@@ -37,38 +37,45 @@ export class HWebAuth {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Autentica um usuário
|
|
40
|
+
* Autentica um usuário usando um provider específico
|
|
41
41
|
*/
|
|
42
|
-
async signIn(
|
|
43
|
-
const
|
|
44
|
-
if (!
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (!authProvider.authorize) {
|
|
42
|
+
async signIn(providerId: string, credentials: Record<string, string>): Promise<{ session: Session; token: string } | { redirectUrl: string } | null> {
|
|
43
|
+
const provider = this.config.providers.find(p => p.id === providerId);
|
|
44
|
+
if (!provider) {
|
|
45
|
+
console.error(`[hweb-auth] Provider not found: ${providerId}`);
|
|
49
46
|
return null;
|
|
50
47
|
}
|
|
51
48
|
|
|
52
49
|
try {
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
// Usa o método handleSignIn do provider
|
|
51
|
+
const result = await provider.handleSignIn(credentials);
|
|
52
|
+
|
|
53
|
+
if (!result) return null;
|
|
54
|
+
|
|
55
|
+
// Se resultado é string, é URL de redirecionamento OAuth
|
|
56
|
+
if (typeof result === 'string') {
|
|
57
|
+
return { redirectUrl: result };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Se resultado é User, cria sessão
|
|
61
|
+
const user = result as User;
|
|
55
62
|
|
|
56
63
|
// Callback de signIn se definido
|
|
57
64
|
if (this.config.callbacks?.signIn) {
|
|
58
|
-
const allowed = await this.config.callbacks.signIn(user, { provider }, {});
|
|
65
|
+
const allowed = await this.config.callbacks.signIn(user, { provider: providerId }, {});
|
|
59
66
|
if (!allowed) return null;
|
|
60
67
|
}
|
|
61
68
|
|
|
62
|
-
const
|
|
69
|
+
const sessionResult = this.sessionManager.createSession(user);
|
|
63
70
|
|
|
64
71
|
// Callback de sessão se definido
|
|
65
72
|
if (this.config.callbacks?.session) {
|
|
66
|
-
|
|
73
|
+
sessionResult.session = await this.config.callbacks.session(sessionResult.session, user);
|
|
67
74
|
}
|
|
68
75
|
|
|
69
|
-
return
|
|
76
|
+
return sessionResult;
|
|
70
77
|
} catch (error) {
|
|
71
|
-
console.error(
|
|
78
|
+
console.error(`[hweb-auth] Erro no signIn com provider ${providerId}:`, error);
|
|
72
79
|
return null;
|
|
73
80
|
}
|
|
74
81
|
}
|
|
@@ -76,14 +83,28 @@ export class HWebAuth {
|
|
|
76
83
|
/**
|
|
77
84
|
* Faz logout do usuário
|
|
78
85
|
*/
|
|
79
|
-
signOut(): HightJSResponse {
|
|
86
|
+
async signOut(req: HightJSRequest): Promise<HightJSResponse> {
|
|
87
|
+
// Busca a sessão atual para saber qual provider usar
|
|
88
|
+
const { session } = await this.middleware(req);
|
|
89
|
+
|
|
90
|
+
if (session?.user?.provider) {
|
|
91
|
+
const provider = this.config.providers.find(p => p.id === session.user.provider);
|
|
92
|
+
if (provider && provider.handleSignOut) {
|
|
93
|
+
try {
|
|
94
|
+
await provider.handleSignOut();
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error(`[hweb-auth] Erro no signOut do provider ${provider.id}:`, error);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
80
101
|
return HightJSResponse
|
|
81
102
|
.json({ success: true })
|
|
82
103
|
.clearCookie('hweb-auth-token', {
|
|
83
104
|
path: '/',
|
|
84
105
|
httpOnly: true,
|
|
85
|
-
secure: true,
|
|
86
|
-
sameSite: 'strict'
|
|
106
|
+
secure: true,
|
|
107
|
+
sameSite: 'strict'
|
|
87
108
|
});
|
|
88
109
|
}
|
|
89
110
|
|
|
@@ -103,6 +124,41 @@ export class HWebAuth {
|
|
|
103
124
|
return session !== null;
|
|
104
125
|
}
|
|
105
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Retorna todos os providers disponíveis (dados públicos)
|
|
129
|
+
*/
|
|
130
|
+
getProviders(): any[] {
|
|
131
|
+
return this.config.providers.map(provider => ({
|
|
132
|
+
id: provider.id,
|
|
133
|
+
name: provider.name,
|
|
134
|
+
type: provider.type,
|
|
135
|
+
config: provider.getConfig ? provider.getConfig() : {}
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Busca um provider específico
|
|
141
|
+
*/
|
|
142
|
+
getProvider(id: string): AuthProviderClass | null {
|
|
143
|
+
return this.config.providers.find(p => p.id === id) || null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Retorna todas as rotas adicionais dos providers
|
|
148
|
+
*/
|
|
149
|
+
getAllAdditionalRoutes(): Array<{ provider: string; route: any }> {
|
|
150
|
+
const routes: Array<{ provider: string; route: any }> = [];
|
|
151
|
+
|
|
152
|
+
for (const provider of this.config.providers) {
|
|
153
|
+
if (provider.additionalRoutes) {
|
|
154
|
+
for (const route of provider.additionalRoutes) {
|
|
155
|
+
routes.push({ provider: provider.id, route });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return routes;
|
|
161
|
+
}
|
|
106
162
|
|
|
107
163
|
/**
|
|
108
164
|
* Cria resposta com cookie de autenticação - Secure implementation
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exemplo de como usar os novos providers baseados em classes
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createAuthRoutes } from './routes';
|
|
6
|
+
import { CredentialsProvider, DiscordProvider } from './providers';
|
|
7
|
+
import type { AuthConfig } from './types';
|
|
8
|
+
|
|
9
|
+
// Exemplo de configuração com os novos providers
|
|
10
|
+
const authConfig: AuthConfig = {
|
|
11
|
+
providers: [
|
|
12
|
+
// Provider de credenciais customizado
|
|
13
|
+
new CredentialsProvider({
|
|
14
|
+
name: "Login com Email",
|
|
15
|
+
credentials: {
|
|
16
|
+
email: {
|
|
17
|
+
label: "Email",
|
|
18
|
+
type: "email",
|
|
19
|
+
placeholder: "seu@email.com"
|
|
20
|
+
},
|
|
21
|
+
password: {
|
|
22
|
+
label: "Senha",
|
|
23
|
+
type: "password"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
async authorize(credentials) {
|
|
27
|
+
// Aqui você faz a validação com seu banco de dados
|
|
28
|
+
const { email, password } = credentials;
|
|
29
|
+
|
|
30
|
+
// Exemplo de validação (substitua pela sua lógica)
|
|
31
|
+
if (email === "admin@example.com" && password === "123456") {
|
|
32
|
+
return {
|
|
33
|
+
id: "1",
|
|
34
|
+
name: "Admin User",
|
|
35
|
+
email: email,
|
|
36
|
+
role: "admin"
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Retorna null se credenciais inválidas
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}),
|
|
44
|
+
|
|
45
|
+
// Provider do Discord
|
|
46
|
+
new DiscordProvider({
|
|
47
|
+
clientId: process.env.DISCORD_CLIENT_ID!,
|
|
48
|
+
clientSecret: process.env.DISCORD_CLIENT_SECRET!,
|
|
49
|
+
callbackUrl: "http://localhost:3000/api/auth/callback/discord"
|
|
50
|
+
})
|
|
51
|
+
],
|
|
52
|
+
|
|
53
|
+
secret: process.env.HWEB_AUTH_SECRET || "seu-super-secret-aqui-32-chars-min",
|
|
54
|
+
|
|
55
|
+
session: {
|
|
56
|
+
strategy: 'jwt',
|
|
57
|
+
maxAge: 86400 // 24 horas
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
pages: {
|
|
61
|
+
signIn: '/auth/signin',
|
|
62
|
+
signOut: '/auth/signout'
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
callbacks: {
|
|
66
|
+
async signIn(user, account, profile) {
|
|
67
|
+
// Lógica customizada antes do login
|
|
68
|
+
console.log(`Usuário ${user.email} fazendo login via ${account.provider}`);
|
|
69
|
+
return true; // permitir login
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
async session(session, user) {
|
|
73
|
+
// Adicionar dados customizados à sessão
|
|
74
|
+
return {
|
|
75
|
+
...session,
|
|
76
|
+
user: {
|
|
77
|
+
...session.user,
|
|
78
|
+
customData: "dados extras"
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Criar as rotas de autenticação
|
|
86
|
+
export const authRoutes = createAuthRoutes(authConfig);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Como usar em suas rotas API:
|
|
90
|
+
*
|
|
91
|
+
* // arquivo: /api/auth/[...value].ts
|
|
92
|
+
* import { authRoutes } from '../../../src/auth/example';
|
|
93
|
+
*
|
|
94
|
+
* export const GET = authRoutes.GET;
|
|
95
|
+
* export const POST = authRoutes.POST;
|
|
96
|
+
*/
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Rotas disponíveis automaticamente:
|
|
100
|
+
*
|
|
101
|
+
* Core routes:
|
|
102
|
+
* - GET /api/auth/session - Obter sessão atual
|
|
103
|
+
* - GET /api/auth/providers - Listar providers
|
|
104
|
+
* - GET /api/auth/csrf - Obter token CSRF
|
|
105
|
+
* - POST /api/auth/signin - Login
|
|
106
|
+
* - POST /api/auth/signout - Logout
|
|
107
|
+
*
|
|
108
|
+
* Provider específico (CredentialsProvider):
|
|
109
|
+
* - GET /api/auth/credentials/config - Config do provider
|
|
110
|
+
*
|
|
111
|
+
* Provider específico (DiscordProvider):
|
|
112
|
+
* - GET /api/auth/signin/discord - Iniciar OAuth Discord
|
|
113
|
+
* - GET /api/auth/callback/discord - Callback OAuth Discord
|
|
114
|
+
* - GET /api/auth/discord/config - Config do provider Discord
|
|
115
|
+
*/
|
package/src/auth/index.ts
CHANGED