Improve authentication by conditionally rendering LDAP and OIDC login options and fetching auth provider configurations.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 705f2157-ef97-4fbd-89e4-8c7f2ecaea90
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7ed01c5f-a82d-405a-b728-b2e3d127c60c/4f13eaa5-e266-4ec8-8273-939cfc3ca326.jpg
This commit is contained in:
alphaeusmote
2025-04-10 03:19:57 +00:00
parent 9ccac76b03
commit 8bb52a2a2f
2 changed files with 90 additions and 55 deletions
+27 -1
View File
@@ -1,4 +1,4 @@
import { createContext, ReactNode, useContext } from "react"; import { createContext, ReactNode, useContext, useEffect, useState } from "react";
import { import {
useQuery, useQuery,
useMutation, useMutation,
@@ -17,6 +17,8 @@ type AuthContextType = {
initiateOidcLogin: () => void; initiateOidcLogin: () => void;
logoutMutation: UseMutationResult<void, Error, void>; logoutMutation: UseMutationResult<void, Error, void>;
registerMutation: UseMutationResult<SelectUser, Error, InsertUser>; registerMutation: UseMutationResult<SelectUser, Error, InsertUser>;
ldapEnabled: boolean;
oidcEnabled: boolean;
}; };
type LoginData = Pick<InsertUser, "username" | "password">; type LoginData = Pick<InsertUser, "username" | "password">;
@@ -26,6 +28,9 @@ export const AuthContext = createContext<AuthContextType | null>(null);
export function AuthProvider({ children }: { children: ReactNode }) { export function AuthProvider({ children }: { children: ReactNode }) {
const { toast } = useToast(); const { toast } = useToast();
const [ldapEnabled, setLdapEnabled] = useState(false);
const [oidcEnabled, setOidcEnabled] = useState(false);
const { const {
data: user, data: user,
error, error,
@@ -35,6 +40,25 @@ export function AuthProvider({ children }: { children: ReactNode }) {
queryFn: getQueryFn({ on401: "returnNull" }), queryFn: getQueryFn({ on401: "returnNull" }),
}); });
// Get auth provider configurations
useEffect(() => {
const fetchAuthProviders = async () => {
try {
const response = await fetch('/api/auth/providers');
if (response.ok) {
const providers = await response.json();
setLdapEnabled(providers.ldap?.enabled || false);
setOidcEnabled(providers.oidc?.enabled || false);
}
} catch (err) {
// Silently fail - default is disabled
console.error('Failed to fetch auth providers:', err);
}
};
fetchAuthProviders();
}, []);
const loginMutation = useMutation({ const loginMutation = useMutation({
mutationFn: async (credentials: LoginData) => { mutationFn: async (credentials: LoginData) => {
const res = await apiRequest("POST", "/api/login", credentials); const res = await apiRequest("POST", "/api/login", credentials);
@@ -133,6 +157,8 @@ export function AuthProvider({ children }: { children: ReactNode }) {
initiateOidcLogin, initiateOidcLogin,
logoutMutation, logoutMutation,
registerMutation, registerMutation,
ldapEnabled,
oidcEnabled,
}; };
return ( return (
+60 -51
View File
@@ -234,61 +234,70 @@ export default function AuthPage() {
{auth.loginMutation.isPending ? "Logging in..." : "Log in"} {auth.loginMutation.isPending ? "Logging in..." : "Log in"}
</Button> </Button>
<div className="relative my-5"> {/* Only show additional login methods when they are configured */}
<div className="absolute inset-0 flex items-center"> {(auth.ldapEnabled || auth.oidcEnabled) && (
<span className="w-full border-t border-gray-300"></span> <>
</div> <div className="relative my-5">
<div className="relative flex justify-center text-sm"> <div className="absolute inset-0 flex items-center">
<span className="px-2 bg-white text-gray-500">Or continue with</span> <span className="w-full border-t border-gray-300"></span>
</div> </div>
</div> <div className="relative flex justify-center text-sm">
<span className="px-2 bg-white text-gray-500">Or continue with</span>
</div>
</div>
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
<Button {auth.ldapEnabled && (
type="button" <Button
variant="outline" type="button"
className="w-full" variant="outline"
disabled={auth.ldapLoginMutation.isPending || auth.loginMutation.isPending} className="w-full"
onClick={() => { disabled={auth.ldapLoginMutation.isPending || auth.loginMutation.isPending}
const username = loginForm.getValues("username"); onClick={() => {
const password = loginForm.getValues("password"); const username = loginForm.getValues("username");
const password = loginForm.getValues("password");
// Validate the fields // Validate the fields
if (!username || !password) { if (!username || !password) {
loginForm.setError("username", { loginForm.setError("username", {
type: "manual", type: "manual",
message: !username ? "Username is required" : undefined message: !username ? "Username is required" : undefined
}); });
loginForm.setError("password", { loginForm.setError("password", {
type: "manual", type: "manual",
message: !password ? "Password is required" : undefined message: !password ? "Password is required" : undefined
}); });
return; return;
} }
auth.ldapLoginMutation.mutate( auth.ldapLoginMutation.mutate(
{ username, password }, { username, password },
{ {
onSuccess: () => { onSuccess: () => {
navigate("/"); navigate("/");
} }
} }
); );
}} }}
> >
{auth.ldapLoginMutation.isPending ? "Authenticating..." : "LDAP Login"} {auth.ldapLoginMutation.isPending ? "Authenticating..." : "LDAP Login"}
</Button> </Button>
)}
<Button {auth.oidcEnabled && (
type="button" <Button
variant="outline" type="button"
className="w-full" variant="outline"
disabled={auth.ldapLoginMutation.isPending || auth.loginMutation.isPending} className={`w-full ${!auth.ldapEnabled ? "col-span-2" : ""}`}
onClick={() => auth.initiateOidcLogin()} disabled={auth.ldapLoginMutation.isPending || auth.loginMutation.isPending}
> onClick={() => auth.initiateOidcLogin()}
OpenID Connect >
</Button> OpenID Connect
</div> </Button>
)}
</div>
</>
)}
</form> </form>
</Form> </Form>
</CardContent> </CardContent>