@checkmate-monitor/auth-frontend 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/CHANGELOG.md +55 -0
- package/e2e/login.e2e.ts +63 -0
- package/package.json +34 -0
- package/playwright-report/data/774b616fd991c36e57f6aa95d67906b877dff5d1.md +20 -0
- package/playwright-report/data/d37ef869a8ef03c489f7ca3b80d67da69614c383.png +3 -0
- package/playwright-report/index.html +85 -0
- package/playwright.config.ts +5 -0
- package/src/api.ts +77 -0
- package/src/components/AuthErrorPage.tsx +94 -0
- package/src/components/AuthSettingsPage.tsx +1206 -0
- package/src/components/AuthStrategyCard.tsx +73 -0
- package/src/components/CreateUserDialog.tsx +156 -0
- package/src/components/ForgotPasswordPage.tsx +130 -0
- package/src/components/LoginPage.tsx +302 -0
- package/src/components/RegisterPage.tsx +349 -0
- package/src/components/ResetPasswordPage.tsx +261 -0
- package/src/components/RoleDialog.tsx +284 -0
- package/src/components/SocialProviderButton.tsx +55 -0
- package/src/hooks/useEnabledStrategies.ts +54 -0
- package/src/hooks/usePermissions.ts +36 -0
- package/src/index.test.tsx +95 -0
- package/src/index.tsx +241 -0
- package/src/lib/auth-client.ts +6 -0
- package/test-results/login-Login-Page-should-show-login-form-elements-chromium/test-failed-1.png +3 -0
- package/tsconfig.json +6 -0
package/src/api.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { createApiRef } from "@checkmate-monitor/frontend-api";
|
|
2
|
+
|
|
3
|
+
// Types for better-auth entities
|
|
4
|
+
export interface AuthUser {
|
|
5
|
+
id: string;
|
|
6
|
+
email: string;
|
|
7
|
+
name?: string;
|
|
8
|
+
image?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface AuthSession {
|
|
12
|
+
session: {
|
|
13
|
+
id: string;
|
|
14
|
+
userId: string;
|
|
15
|
+
token: string;
|
|
16
|
+
expiresAt: Date;
|
|
17
|
+
};
|
|
18
|
+
user: AuthUser;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface Role {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
description?: string | null;
|
|
25
|
+
isSystem?: boolean;
|
|
26
|
+
isAssignable?: boolean; // False for anonymous role - not assignable to users
|
|
27
|
+
permissions?: string[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface Permission {
|
|
31
|
+
id: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface AuthStrategy {
|
|
36
|
+
id: string;
|
|
37
|
+
displayName: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
icon?: string; // Lucide icon name
|
|
40
|
+
enabled: boolean;
|
|
41
|
+
configVersion: number;
|
|
42
|
+
configSchema: Record<string, unknown>; // JSON Schema
|
|
43
|
+
config?: Record<string, unknown>;
|
|
44
|
+
adminInstructions?: string; // Markdown instructions for admins
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface EnabledAuthStrategy {
|
|
48
|
+
id: string;
|
|
49
|
+
displayName: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
type: "credential" | "social";
|
|
52
|
+
icon?: string; // Lucide icon name
|
|
53
|
+
requiresManualRegistration: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* AuthApi provides better-auth client methods for authentication.
|
|
58
|
+
* For RPC calls (including getEnabledStrategies, user/role/strategy management), use:
|
|
59
|
+
* const authClient = rpcApiRef.forPlugin<AuthClient>("auth");
|
|
60
|
+
*/
|
|
61
|
+
export interface AuthApi {
|
|
62
|
+
// Better-auth methods (not RPC)
|
|
63
|
+
signIn(
|
|
64
|
+
email: string,
|
|
65
|
+
password: string
|
|
66
|
+
): Promise<{ data?: AuthSession; error?: Error }>;
|
|
67
|
+
signInWithSocial(provider: string): Promise<void>;
|
|
68
|
+
signOut(): Promise<void>;
|
|
69
|
+
getSession(): Promise<{ data?: AuthSession; error?: Error }>;
|
|
70
|
+
useSession(): {
|
|
71
|
+
data?: AuthSession;
|
|
72
|
+
isPending: boolean;
|
|
73
|
+
error?: Error;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const authApiRef = createApiRef<AuthApi>("auth.api");
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Link, useSearchParams } from "react-router-dom";
|
|
2
|
+
import { AlertCircle, Home, LogIn } from "lucide-react";
|
|
3
|
+
import { authRoutes } from "@checkmate-monitor/auth-common";
|
|
4
|
+
import { resolveRoute } from "@checkmate-monitor/common";
|
|
5
|
+
import {
|
|
6
|
+
Button,
|
|
7
|
+
Card,
|
|
8
|
+
CardHeader,
|
|
9
|
+
CardTitle,
|
|
10
|
+
CardDescription,
|
|
11
|
+
CardContent,
|
|
12
|
+
CardFooter,
|
|
13
|
+
Alert,
|
|
14
|
+
AlertIcon,
|
|
15
|
+
AlertContent,
|
|
16
|
+
AlertTitle,
|
|
17
|
+
AlertDescription,
|
|
18
|
+
} from "@checkmate-monitor/ui";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Map technical error messages to user-friendly ones
|
|
22
|
+
*/
|
|
23
|
+
const getErrorMessage = (error: string | undefined): string => {
|
|
24
|
+
if (!error) {
|
|
25
|
+
return "An unexpected error occurred during authentication.";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Registration disabled error
|
|
29
|
+
if (error.includes("Registration is currently disabled")) {
|
|
30
|
+
return "Registration is currently disabled. Please contact an administrator if you need access.";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// User denied authorization
|
|
34
|
+
if (error.includes("access_denied") || error.includes("user_denied")) {
|
|
35
|
+
return "Authorization was cancelled. Please try again if you wish to sign in.";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Generic OAuth errors
|
|
39
|
+
if (error.includes("UNKNOWN") || error.includes("unknown")) {
|
|
40
|
+
return "An unexpected error occurred. Please try again or contact support if the problem persists.";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Return the error as-is if it seems user-friendly
|
|
44
|
+
return error;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const AuthErrorPage = () => {
|
|
48
|
+
const [searchParams] = useSearchParams();
|
|
49
|
+
const errorParam = searchParams.get("error");
|
|
50
|
+
|
|
51
|
+
// better-auth encodes error messages using underscores for spaces
|
|
52
|
+
// Decode by replacing underscores with spaces
|
|
53
|
+
const decodedError = errorParam?.replaceAll("_", " ") ?? undefined;
|
|
54
|
+
|
|
55
|
+
const errorMessage = getErrorMessage(decodedError);
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div className="min-h-[80vh] flex items-center justify-center">
|
|
59
|
+
<Card className="w-full max-w-md">
|
|
60
|
+
<CardHeader className="flex flex-col space-y-1 items-center">
|
|
61
|
+
<CardTitle>Authentication Error</CardTitle>
|
|
62
|
+
<CardDescription>
|
|
63
|
+
We encountered a problem during sign-in
|
|
64
|
+
</CardDescription>
|
|
65
|
+
</CardHeader>
|
|
66
|
+
<CardContent>
|
|
67
|
+
<Alert variant="error">
|
|
68
|
+
<AlertIcon>
|
|
69
|
+
<AlertCircle className="h-4 w-4" />
|
|
70
|
+
</AlertIcon>
|
|
71
|
+
<AlertContent>
|
|
72
|
+
<AlertTitle>Sign-in Failed</AlertTitle>
|
|
73
|
+
<AlertDescription>{errorMessage}</AlertDescription>
|
|
74
|
+
</AlertContent>
|
|
75
|
+
</Alert>
|
|
76
|
+
</CardContent>
|
|
77
|
+
<CardFooter className="flex gap-2 justify-center">
|
|
78
|
+
<Link to={resolveRoute(authRoutes.routes.login)}>
|
|
79
|
+
<Button variant="primary">
|
|
80
|
+
<LogIn className="mr-2 h-4 w-4" />
|
|
81
|
+
Try Again
|
|
82
|
+
</Button>
|
|
83
|
+
</Link>
|
|
84
|
+
<Link to="/">
|
|
85
|
+
<Button variant="outline">
|
|
86
|
+
<Home className="mr-2 h-4 w-4" />
|
|
87
|
+
Go Home
|
|
88
|
+
</Button>
|
|
89
|
+
</Link>
|
|
90
|
+
</CardFooter>
|
|
91
|
+
</Card>
|
|
92
|
+
</div>
|
|
93
|
+
);
|
|
94
|
+
};
|