@plyaz/auth 1.0.0 → 1.0.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/commits.txt +3 -3
- package/dist/common/index.cjs +3 -1
- package/dist/common/index.cjs.map +1 -1
- package/dist/common/index.mjs +3 -1
- package/dist/common/index.mjs.map +1 -1
- package/dist/index.cjs +424 -154
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +421 -152
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/release_message.txt +28 -0
- package/src/adapters/auth-adapter-factory.ts +4 -3
- package/src/adapters/auth-adapter.mapper.ts +2 -2
- package/src/adapters/base-auth.adapter.ts +17 -9
- package/src/adapters/clerk/clerk.adapter.ts +9 -12
- package/src/adapters/custom/custom.adapter.ts +19 -10
- package/src/adapters/index.ts +0 -1
- package/src/adapters/next-auth/authOptions.ts +20 -16
- package/src/adapters/next-auth/next-auth.adapter.ts +13 -15
- package/src/api/client.ts +4 -6
- package/src/audit/audit.logger.ts +19 -10
- package/src/client/components/ProtectedRoute.tsx +15 -11
- package/src/client/hooks/useAuth.ts +23 -21
- package/src/client/hooks/useConnectedAccounts.ts +57 -45
- package/src/client/hooks/usePermissions.ts +1 -1
- package/src/client/hooks/useRBAC.ts +6 -6
- package/src/client/hooks/useSession.ts +5 -5
- package/src/client/providers/AuthProvider.tsx +23 -17
- package/src/client/store/auth.store.ts +71 -62
- package/src/client/utils/storage.ts +45 -18
- package/src/common/constants/oauth-providers.ts +10 -7
- package/src/common/errors/auth.errors.ts +4 -4
- package/src/common/errors/specific-auth-errors.ts +5 -9
- package/src/common/regex/index.ts +6 -4
- package/src/common/types/auth.types.ts +47 -38
- package/src/common/types/index.ts +12 -6
- package/src/common/utils/index.ts +15 -11
- package/src/core/blacklist/token.blacklist.ts +13 -7
- package/src/core/index.ts +2 -2
- package/src/core/jwt/jwt.manager.ts +47 -22
- package/src/core/session/session.manager.ts +17 -14
- package/src/db/repositories/connected-account.repository.ts +120 -78
- package/src/db/repositories/role.repository.ts +41 -26
- package/src/db/repositories/session.repository.ts +9 -10
- package/src/db/repositories/user.repository.ts +105 -91
- package/src/flows/index.ts +2 -2
- package/src/flows/sign-in.flow.ts +28 -14
- package/src/flows/sign-up.flow.ts +31 -20
- package/src/index.ts +36 -37
- package/src/libs/clerk.helper.ts +6 -7
- package/src/libs/supabase.helper.ts +79 -61
- package/src/libs/supabaseClient.ts +3 -3
- package/src/providers/base/auth-provider.interface.ts +13 -11
- package/src/providers/base/index.ts +1 -1
- package/src/providers/index.ts +1 -1
- package/src/providers/oauth/facebook.provider.ts +63 -39
- package/src/providers/oauth/github.provider.ts +14 -10
- package/src/providers/oauth/google.provider.ts +39 -28
- package/src/providers/oauth/index.ts +1 -1
- package/src/rbac/dynamic-roles.ts +88 -54
- package/src/rbac/index.ts +4 -4
- package/src/rbac/permission-checker.ts +147 -75
- package/src/rbac/role-hierarchy.ts +8 -8
- package/src/rbac/role.manager.ts +11 -8
- package/src/security/csrf/csrf.protection.ts +9 -7
- package/src/security/index.ts +2 -2
- package/src/security/rate-limiting/auth/auth.controller.ts +2 -4
- package/src/security/rate-limiting/auth/rate-limiting.interface.ts +26 -6
- package/src/security/rate-limiting/auth.module.ts +1 -2
- package/src/server/auth.module.ts +55 -52
- package/src/server/decorators/auth.decorator.ts +9 -11
- package/src/server/decorators/auth.decorators.ts +8 -9
- package/src/server/decorators/current-user.decorator.ts +6 -6
- package/src/server/decorators/permission.decorator.ts +17 -9
- package/src/server/guards/auth.guard.ts +21 -16
- package/src/server/guards/custom-throttler.guard.ts +4 -9
- package/src/server/guards/permissions.guard.ts +32 -23
- package/src/server/guards/roles.guard.ts +14 -12
- package/src/server/middleware/auth.middleware.ts +4 -4
- package/src/server/middleware/session.middleware.ts +4 -4
- package/src/server/services/account.service.ts +96 -48
- package/src/server/services/auth.service.ts +57 -28
- package/src/server/services/brute-force.service.ts +24 -19
- package/src/server/services/index.ts +1 -1
- package/src/server/services/rate-limiter.service.ts +9 -4
- package/src/server/services/session.service.ts +84 -48
- package/src/server/services/token.service.ts +71 -51
- package/src/session/cookie-store.ts +47 -34
- package/src/session/enhanced-session-manager.ts +69 -48
- package/src/session/index.ts +5 -5
- package/src/session/memory-store.ts +37 -30
- package/src/session/redis-store.ts +105 -72
- package/src/strategies/oauth.strategy.ts +10 -9
- package/src/strategies/traditional-auth.strategy.ts +41 -29
- package/src/tokens/index.ts +4 -4
- package/src/tokens/refresh-token-manager.ts +70 -55
- package/src/tokens/token-validator.ts +109 -53
- package/vitest.setup.d.ts +2 -2
- package/vitest.setup.ts +1 -1
|
@@ -6,7 +6,6 @@ import type {
|
|
|
6
6
|
AuthSession,
|
|
7
7
|
AuthUser,
|
|
8
8
|
Tokens,
|
|
9
|
-
|
|
10
9
|
ConnectedAccount,
|
|
11
10
|
} from "@plyaz/types";
|
|
12
11
|
|
|
@@ -27,7 +26,10 @@ export interface UseAuthReturn {
|
|
|
27
26
|
isAuthenticated: boolean;
|
|
28
27
|
isLoading: boolean;
|
|
29
28
|
error: string | null;
|
|
30
|
-
signIn: (
|
|
29
|
+
signIn: (
|
|
30
|
+
provider?: AUTHPROVIDER,
|
|
31
|
+
credentials?: AuthCredentials,
|
|
32
|
+
) => Promise<{
|
|
31
33
|
user: AuthAdapterUser;
|
|
32
34
|
session: AuthSession;
|
|
33
35
|
tokens: Tokens;
|
|
@@ -35,7 +37,9 @@ export interface UseAuthReturn {
|
|
|
35
37
|
signUp: (provider: AUTHPROVIDER, data?: unknown) => Promise<void>;
|
|
36
38
|
signOut: () => Promise<void>;
|
|
37
39
|
linkAccount: (
|
|
38
|
-
|
|
40
|
+
userId: string,
|
|
41
|
+
provider: AUTHPROVIDER,
|
|
42
|
+
data: ConnectedAccount,
|
|
39
43
|
) => Promise<void | ConnectedAccount>;
|
|
40
44
|
unlinkAccount: (accountId: string) => Promise<void>;
|
|
41
45
|
}
|
|
@@ -51,25 +55,20 @@ export function useAuth(): UseAuthReturn {
|
|
|
51
55
|
* @private
|
|
52
56
|
*/
|
|
53
57
|
|
|
54
|
-
const handleAuthAction = async <T
|
|
55
|
-
action: () => Promise<T>
|
|
56
|
-
): Promise<T> => {
|
|
58
|
+
const handleAuthAction = async <T>(action: () => Promise<T>): Promise<T> => {
|
|
57
59
|
store.setLoading(true);
|
|
58
60
|
store.setError(null);
|
|
59
61
|
|
|
60
62
|
try {
|
|
61
63
|
const result = await action();
|
|
62
64
|
return result;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
err instanceof Error ? err.message : "Authentication failed";
|
|
67
|
-
|
|
68
|
-
store.setError(errorMessage);
|
|
69
|
-
throw err;
|
|
70
|
-
}
|
|
65
|
+
} catch (err: unknown) {
|
|
66
|
+
const errorMessage =
|
|
67
|
+
err instanceof Error ? err.message : "Authentication failed";
|
|
71
68
|
|
|
72
|
-
|
|
69
|
+
store.setError(errorMessage);
|
|
70
|
+
throw err;
|
|
71
|
+
} finally {
|
|
73
72
|
store.setLoading(false);
|
|
74
73
|
}
|
|
75
74
|
};
|
|
@@ -81,7 +80,7 @@ export function useAuth(): UseAuthReturn {
|
|
|
81
80
|
error: store.error,
|
|
82
81
|
signIn: async (
|
|
83
82
|
provider?: AUTHPROVIDER,
|
|
84
|
-
credentials?: AuthCredentials
|
|
83
|
+
credentials?: AuthCredentials,
|
|
85
84
|
): Promise<{
|
|
86
85
|
user: AuthAdapterUser;
|
|
87
86
|
session: AuthSession;
|
|
@@ -99,12 +98,13 @@ export function useAuth(): UseAuthReturn {
|
|
|
99
98
|
},
|
|
100
99
|
|
|
101
100
|
linkAccount: async (
|
|
102
|
-
|
|
101
|
+
userId: string,
|
|
102
|
+
provider: AUTHPROVIDER,
|
|
103
|
+
data: ConnectedAccount,
|
|
103
104
|
): Promise<void> => {
|
|
104
105
|
return handleAuthAction(async () => {
|
|
105
106
|
// Construct a ConnectedAccount object; adjust fields as needed
|
|
106
107
|
const connectedAccount: ConnectedAccount = {
|
|
107
|
-
|
|
108
108
|
...data,
|
|
109
109
|
userId,
|
|
110
110
|
provider,
|
|
@@ -115,14 +115,16 @@ export function useAuth(): UseAuthReturn {
|
|
|
115
115
|
isActive: false,
|
|
116
116
|
linkedAt: new Date(),
|
|
117
117
|
createdAt: new Date(),
|
|
118
|
-
updatedAt: new Date()
|
|
118
|
+
updatedAt: new Date(),
|
|
119
119
|
};
|
|
120
120
|
store.addConnectedAccount(connectedAccount);
|
|
121
121
|
});
|
|
122
122
|
},
|
|
123
123
|
|
|
124
124
|
unlinkAccount: async (accountId: string): Promise<void> => {
|
|
125
|
-
return handleAuthAction(async () =>
|
|
125
|
+
return handleAuthAction(async () =>
|
|
126
|
+
store.removeConnectedAccount(accountId),
|
|
127
|
+
);
|
|
126
128
|
},
|
|
127
129
|
};
|
|
128
|
-
}
|
|
130
|
+
}
|
|
@@ -3,14 +3,17 @@
|
|
|
3
3
|
* @module @plyaz/auth/client/hooks/useConnectedAccounts
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { useState, useEffect } from
|
|
7
|
-
import { useAuth } from
|
|
8
|
-
import type { AuthCredentials, ConnectedAccount } from
|
|
6
|
+
import { useState, useEffect } from "react";
|
|
7
|
+
import { useAuth } from "./useAuth";
|
|
8
|
+
import type { AuthCredentials, ConnectedAccount } from "@plyaz/types";
|
|
9
9
|
|
|
10
10
|
export interface UseConnectedAccountsReturn {
|
|
11
11
|
accounts: ConnectedAccount[];
|
|
12
12
|
isLoading: boolean;
|
|
13
|
-
linkAccount: (
|
|
13
|
+
linkAccount: (
|
|
14
|
+
provider: string,
|
|
15
|
+
credentials: AuthCredentials,
|
|
16
|
+
) => Promise<void>;
|
|
14
17
|
unlinkAccount: (accountId: string) => Promise<void>;
|
|
15
18
|
setPrimaryAccount: (accountId: string) => Promise<void>;
|
|
16
19
|
refreshAccounts: () => Promise<void>;
|
|
@@ -21,67 +24,78 @@ export const useConnectedAccounts = (): UseConnectedAccountsReturn => {
|
|
|
21
24
|
const [isLoading, setIsLoading] = useState(true);
|
|
22
25
|
const { user } = useAuth();
|
|
23
26
|
|
|
24
|
-
const linkAccount = async (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
const linkAccount = async (
|
|
28
|
+
provider: string,
|
|
29
|
+
credentials: AuthCredentials,
|
|
30
|
+
): Promise<void> => {
|
|
31
|
+
if (!user) throw new Error("User not authenticated");
|
|
32
|
+
|
|
27
33
|
setIsLoading(true);
|
|
28
34
|
try {
|
|
29
|
-
const response = await globalThis.fetch(
|
|
30
|
-
method:
|
|
31
|
-
headers: {
|
|
32
|
-
body: JSON.stringify({ provider, credentials })
|
|
35
|
+
const response = await globalThis.fetch("/api/auth/accounts/link", {
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: { "Content-Type": "application/json" },
|
|
38
|
+
body: JSON.stringify({ provider, credentials }),
|
|
33
39
|
});
|
|
34
|
-
|
|
35
|
-
if (!response.ok) throw new Error(
|
|
36
|
-
|
|
37
|
-
const newAccount = await response.json() as ConnectedAccount;
|
|
38
|
-
setAccounts(prev => [...prev, newAccount]);
|
|
40
|
+
|
|
41
|
+
if (!response.ok) throw new Error("Failed to link account");
|
|
42
|
+
|
|
43
|
+
const newAccount = (await response.json()) as ConnectedAccount;
|
|
44
|
+
setAccounts((prev) => [...prev, newAccount]);
|
|
39
45
|
} finally {
|
|
40
46
|
setIsLoading(false);
|
|
41
47
|
}
|
|
42
48
|
};
|
|
43
49
|
|
|
44
|
-
const unlinkAccount = async (accountId: string):Promise<void> => {
|
|
50
|
+
const unlinkAccount = async (accountId: string): Promise<void> => {
|
|
45
51
|
setIsLoading(true);
|
|
46
52
|
try {
|
|
47
|
-
const response = await globalThis.fetch(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
const response = await globalThis.fetch(
|
|
54
|
+
`/api/auth/accounts/${accountId}/unlink`,
|
|
55
|
+
{
|
|
56
|
+
method: "DELETE",
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
if (!response.ok) throw new Error("Failed to unlink account");
|
|
61
|
+
|
|
62
|
+
setAccounts((prev) => prev.filter((acc) => acc.id !== accountId));
|
|
54
63
|
} finally {
|
|
55
64
|
setIsLoading(false);
|
|
56
65
|
}
|
|
57
66
|
};
|
|
58
67
|
|
|
59
|
-
const setPrimaryAccount = async (accountId: string):Promise<void> => {
|
|
68
|
+
const setPrimaryAccount = async (accountId: string): Promise<void> => {
|
|
60
69
|
setIsLoading(true);
|
|
61
70
|
try {
|
|
62
|
-
const response = await globalThis.fetch(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
const response = await globalThis.fetch(
|
|
72
|
+
`/api/auth/accounts/${accountId}/primary`,
|
|
73
|
+
{
|
|
74
|
+
method: "PUT",
|
|
75
|
+
},
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
if (!response.ok) throw new Error("Failed to set primary account");
|
|
79
|
+
|
|
80
|
+
setAccounts((prev) =>
|
|
81
|
+
prev.map((acc) => ({
|
|
82
|
+
...acc,
|
|
83
|
+
isPrimary: acc.id === accountId,
|
|
84
|
+
})),
|
|
85
|
+
);
|
|
72
86
|
} finally {
|
|
73
87
|
setIsLoading(false);
|
|
74
88
|
}
|
|
75
89
|
};
|
|
76
90
|
|
|
77
|
-
const refreshAccounts = async ():Promise<void
|
|
91
|
+
const refreshAccounts = async (): Promise<void> => {
|
|
78
92
|
if (!user) return;
|
|
79
|
-
|
|
93
|
+
|
|
80
94
|
setIsLoading(true);
|
|
81
95
|
try {
|
|
82
|
-
const response = await globalThis.fetch(
|
|
96
|
+
const response = await globalThis.fetch("/api/auth/accounts");
|
|
83
97
|
if (response.ok) {
|
|
84
|
-
const data = await response.json() as ConnectedAccount[];
|
|
98
|
+
const data = (await response.json()) as ConnectedAccount[];
|
|
85
99
|
setAccounts(data);
|
|
86
100
|
}
|
|
87
101
|
} finally {
|
|
@@ -90,11 +104,9 @@ export const useConnectedAccounts = (): UseConnectedAccountsReturn => {
|
|
|
90
104
|
};
|
|
91
105
|
|
|
92
106
|
useEffect(() => {
|
|
93
|
-
void (async():Promise<void> => {
|
|
94
|
-
|
|
95
|
-
})();
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
void (async (): Promise<void> => {
|
|
108
|
+
await refreshAccounts();
|
|
109
|
+
})();
|
|
98
110
|
}, [user]);
|
|
99
111
|
|
|
100
112
|
return {
|
|
@@ -105,4 +117,4 @@ export const useConnectedAccounts = (): UseConnectedAccountsReturn => {
|
|
|
105
117
|
setPrimaryAccount,
|
|
106
118
|
refreshAccounts,
|
|
107
119
|
};
|
|
108
|
-
};
|
|
120
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useAuth } from
|
|
1
|
+
import { useAuth } from "./useAuth";
|
|
2
2
|
|
|
3
3
|
export interface UseRBACReturn {
|
|
4
4
|
hasRole: (role: string) => boolean;
|
|
@@ -18,11 +18,11 @@ export const useRBAC = (): UseRBACReturn => {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
const hasAnyRole = (roles: string[]): boolean => {
|
|
21
|
-
return roles.some(role => userRoles.includes(role));
|
|
21
|
+
return roles.some((role) => userRoles.includes(role));
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
const hasAllRoles = (roles: string[]): boolean => {
|
|
25
|
-
return roles.every(role => userRoles.includes(role));
|
|
25
|
+
return roles.every((role) => userRoles.includes(role));
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
return {
|
|
@@ -30,7 +30,7 @@ export const useRBAC = (): UseRBACReturn => {
|
|
|
30
30
|
hasAnyRole,
|
|
31
31
|
hasAllRoles,
|
|
32
32
|
userRoles,
|
|
33
|
-
isAdmin: hasRole(
|
|
34
|
-
isModerator: hasRole(
|
|
33
|
+
isAdmin: hasRole("ADMIN"),
|
|
34
|
+
isModerator: hasRole("MODERATOR"),
|
|
35
35
|
};
|
|
36
|
-
};
|
|
36
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Session } from "@plyaz/types";
|
|
2
2
|
import { useAuthStore } from "../store/auth.store";
|
|
3
3
|
|
|
4
|
-
export function useSession()
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
export function useSession(): {
|
|
5
|
+
session: Session | null;
|
|
6
|
+
isValid: boolean;
|
|
7
|
+
expiresAt: Date | null;
|
|
8
|
+
refresh: () => Promise<void>;
|
|
9
9
|
} {
|
|
10
10
|
const store = useAuthStore();
|
|
11
11
|
|
|
@@ -2,13 +2,13 @@ import type { ReactNode } from "react";
|
|
|
2
2
|
import { createContext } from "react";
|
|
3
3
|
import type { UseAuthReturn } from "../hooks/useAuth";
|
|
4
4
|
import { useAuthStore } from "../store/auth.store";
|
|
5
|
-
import type
|
|
6
|
-
AuthCredentials,
|
|
7
|
-
AUTHPROVIDER,
|
|
8
|
-
ConnectedAccount,
|
|
5
|
+
import type {
|
|
6
|
+
AuthCredentials,
|
|
7
|
+
AUTHPROVIDER,
|
|
8
|
+
ConnectedAccount,
|
|
9
9
|
AuthAdapterUser,
|
|
10
10
|
AuthSession,
|
|
11
|
-
Tokens
|
|
11
|
+
Tokens,
|
|
12
12
|
} from "@plyaz/types";
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -27,9 +27,7 @@ export function AuthProvider({ children }: { children: ReactNode }): ReactNode {
|
|
|
27
27
|
const store = useAuthStore();
|
|
28
28
|
|
|
29
29
|
// Wrap actions in a helper to handle loading and errors
|
|
30
|
-
const handleAuthAction = async <T,>(
|
|
31
|
-
action: () => Promise<T>
|
|
32
|
-
): Promise<T> => {
|
|
30
|
+
const handleAuthAction = async <T,>(action: () => Promise<T>): Promise<T> => {
|
|
33
31
|
store.setLoading(true);
|
|
34
32
|
store.setError(null);
|
|
35
33
|
|
|
@@ -54,7 +52,10 @@ export function AuthProvider({ children }: { children: ReactNode }): ReactNode {
|
|
|
54
52
|
error: store.error,
|
|
55
53
|
|
|
56
54
|
// Auth API actions wrapped with handleAuthAction
|
|
57
|
-
signIn: async (
|
|
55
|
+
signIn: async (
|
|
56
|
+
provider?: AUTHPROVIDER,
|
|
57
|
+
credentials?: AuthCredentials,
|
|
58
|
+
): Promise<{
|
|
58
59
|
user: AuthAdapterUser;
|
|
59
60
|
session: AuthSession;
|
|
60
61
|
tokens: Tokens;
|
|
@@ -62,7 +63,11 @@ export function AuthProvider({ children }: { children: ReactNode }): ReactNode {
|
|
|
62
63
|
return handleAuthAction(() => store.signIn(provider, credentials));
|
|
63
64
|
},
|
|
64
65
|
|
|
65
|
-
signUp: async (
|
|
66
|
+
signUp: async (
|
|
67
|
+
provider: AUTHPROVIDER,
|
|
68
|
+
credentials: unknown,
|
|
69
|
+
data?: unknown,
|
|
70
|
+
) => {
|
|
66
71
|
return handleAuthAction(() => store.signUp(provider, data));
|
|
67
72
|
},
|
|
68
73
|
|
|
@@ -70,11 +75,14 @@ export function AuthProvider({ children }: { children: ReactNode }): ReactNode {
|
|
|
70
75
|
return handleAuthAction(() => store.signOut());
|
|
71
76
|
},
|
|
72
77
|
|
|
73
|
-
linkAccount: async (
|
|
78
|
+
linkAccount: async (
|
|
79
|
+
userId: string,
|
|
80
|
+
provider: AUTHPROVIDER,
|
|
81
|
+
data: ConnectedAccount,
|
|
82
|
+
): Promise<void | ConnectedAccount> => {
|
|
74
83
|
return handleAuthAction(async () => {
|
|
75
84
|
// Create a minimal ConnectedAccount object with only required properties
|
|
76
85
|
const connectedAccount: ConnectedAccount = {
|
|
77
|
-
|
|
78
86
|
...data,
|
|
79
87
|
userId,
|
|
80
88
|
provider,
|
|
@@ -85,7 +93,7 @@ export function AuthProvider({ children }: { children: ReactNode }): ReactNode {
|
|
|
85
93
|
isActive: false,
|
|
86
94
|
linkedAt: new Date(),
|
|
87
95
|
createdAt: new Date(),
|
|
88
|
-
updatedAt: new Date()
|
|
96
|
+
updatedAt: new Date(),
|
|
89
97
|
};
|
|
90
98
|
store.addConnectedAccount(connectedAccount);
|
|
91
99
|
});
|
|
@@ -97,8 +105,6 @@ export function AuthProvider({ children }: { children: ReactNode }): ReactNode {
|
|
|
97
105
|
};
|
|
98
106
|
|
|
99
107
|
return (
|
|
100
|
-
<AuthContext.Provider value={authValue}>
|
|
101
|
-
{children}
|
|
102
|
-
</AuthContext.Provider>
|
|
108
|
+
<AuthContext.Provider value={authValue}>{children}</AuthContext.Provider>
|
|
103
109
|
);
|
|
104
|
-
}
|
|
110
|
+
}
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
AuthAdapterUser,
|
|
3
|
+
AuthCredentials,
|
|
4
|
+
AUTHPROVIDER,
|
|
5
|
+
AuthSession,
|
|
6
|
+
AuthTokens,
|
|
7
|
+
AuthUser,
|
|
8
|
+
ConnectedAccount,
|
|
9
|
+
Session,
|
|
10
|
+
Tokens,
|
|
11
|
+
} from "@plyaz/types";
|
|
3
12
|
import { create } from "zustand";
|
|
4
13
|
import { persist, subscribeWithSelector } from "zustand/middleware";
|
|
5
14
|
import type { AuthPermissions } from "../hooks/useAuth";
|
|
6
15
|
|
|
7
|
-
|
|
8
16
|
interface AuthState {
|
|
9
17
|
// User & Authentication
|
|
10
18
|
user: AuthPermissions | null;
|
|
@@ -31,8 +39,6 @@ interface AuthState {
|
|
|
31
39
|
error: string | null;
|
|
32
40
|
}
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
|
|
36
42
|
export interface AuthActions {
|
|
37
43
|
// User Management
|
|
38
44
|
setUser: (user: AuthUser | null) => void;
|
|
@@ -56,9 +62,12 @@ export interface AuthActions {
|
|
|
56
62
|
setRoles: (roles: string[]) => void;
|
|
57
63
|
hasPermission: (permission: string) => boolean;
|
|
58
64
|
hasRole: (role: string) => boolean;
|
|
59
|
-
|
|
65
|
+
|
|
60
66
|
// Authentication Actions
|
|
61
|
-
signIn: (
|
|
67
|
+
signIn: (
|
|
68
|
+
provider?: AUTHPROVIDER,
|
|
69
|
+
credentials?: AuthCredentials,
|
|
70
|
+
) => Promise<{
|
|
62
71
|
user: AuthAdapterUser;
|
|
63
72
|
session: AuthSession;
|
|
64
73
|
tokens: Tokens;
|
|
@@ -134,8 +143,8 @@ export const useAuthStore = create<AuthState & AuthActions>()(
|
|
|
134
143
|
await get().signOut();
|
|
135
144
|
}
|
|
136
145
|
} catch (error: unknown) {
|
|
137
|
-
globalThis.console.log(error)
|
|
138
|
-
|
|
146
|
+
globalThis.console.log(error);
|
|
147
|
+
await get().signOut();
|
|
139
148
|
}
|
|
140
149
|
},
|
|
141
150
|
|
|
@@ -162,7 +171,7 @@ export const useAuthStore = create<AuthState & AuthActions>()(
|
|
|
162
171
|
const { connectedAccounts } = get();
|
|
163
172
|
set({
|
|
164
173
|
connectedAccounts: connectedAccounts.filter(
|
|
165
|
-
(acc) => acc.id !== accountId
|
|
174
|
+
(acc) => acc.id !== accountId,
|
|
166
175
|
),
|
|
167
176
|
});
|
|
168
177
|
},
|
|
@@ -220,55 +229,55 @@ export const useAuthStore = create<AuthState & AuthActions>()(
|
|
|
220
229
|
set({ isLoading: false });
|
|
221
230
|
}
|
|
222
231
|
},
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
},
|
|
232
|
+
signIn: async (provider, credentials) => {
|
|
233
|
+
set({ isLoading: true, error: null });
|
|
234
|
+
try {
|
|
235
|
+
const endpoint = provider
|
|
236
|
+
? `/api/auth/signin/${provider}`
|
|
237
|
+
: "/api/auth/signin";
|
|
238
|
+
const response = await globalThis.fetch(endpoint, {
|
|
239
|
+
method: "POST",
|
|
240
|
+
headers: { "Content-Type": "application/json" },
|
|
241
|
+
body: JSON.stringify(credentials),
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
if (!response.ok) {
|
|
245
|
+
const errorData = (await response.json()) as { message?: string };
|
|
246
|
+
throw new Error(errorData.message ?? "Sign in failed");
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const data = (await response.json()) as {
|
|
250
|
+
user: AuthUser;
|
|
251
|
+
tokens: AuthTokens;
|
|
252
|
+
session: Session;
|
|
253
|
+
};
|
|
254
|
+
const { user, tokens, session } = data;
|
|
255
|
+
|
|
256
|
+
// Update the store state
|
|
257
|
+
set({
|
|
258
|
+
user,
|
|
259
|
+
tokens,
|
|
260
|
+
session,
|
|
261
|
+
isAuthenticated: true,
|
|
262
|
+
lastActivity: new Date(),
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// Return the expected object with proper types
|
|
266
|
+
return {
|
|
267
|
+
user: user as AuthAdapterUser, // Cast to match expected type
|
|
268
|
+
session: session as AuthSession, // Cast to match expected type
|
|
269
|
+
tokens: tokens as Tokens, // Cast to match expected type
|
|
270
|
+
};
|
|
271
|
+
} catch (error: unknown) {
|
|
272
|
+
const errorMessage =
|
|
273
|
+
error instanceof Error ? error.message : "Sign in failed";
|
|
274
|
+
set({ error: errorMessage });
|
|
275
|
+
// Re-throw the error to maintain the Promise rejection
|
|
276
|
+
throw error;
|
|
277
|
+
} finally {
|
|
278
|
+
set({ isLoading: false });
|
|
279
|
+
}
|
|
280
|
+
},
|
|
272
281
|
|
|
273
282
|
signOut: async () => {
|
|
274
283
|
set({ isLoading: true });
|
|
@@ -300,7 +309,7 @@ export const useAuthStore = create<AuthState & AuthActions>()(
|
|
|
300
309
|
rememberMe: state.rememberMe,
|
|
301
310
|
connectedAccounts: state.connectedAccounts,
|
|
302
311
|
}),
|
|
303
|
-
}
|
|
304
|
-
)
|
|
305
|
-
)
|
|
312
|
+
},
|
|
313
|
+
),
|
|
314
|
+
),
|
|
306
315
|
);
|