Add Authentik OIDC login as an additional sign-in option
Local auth stays the primary/always-available login (don't want to lock out the saved admin password) — OIDC is additive, shown as a second button when OIDC_ENABLED=true. Uses openid-client v6 with PKCE. Authentik-side provider was set up via an authentik blueprint (its own declarative automation, see docs/oidc-setup.md) rather than touching any existing admin credentials. Closes #12. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,10 @@ async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
return res.json() as Promise<T>;
|
||||
}
|
||||
|
||||
export function getAuthConfig(): Promise<{ oidcEnabled: boolean }> {
|
||||
return request("/api/auth/config");
|
||||
}
|
||||
|
||||
export function login(username: string, password: string): Promise<{ username: string }> {
|
||||
return request("/api/auth/login", { method: "POST", body: JSON.stringify({ username, password }) });
|
||||
}
|
||||
|
||||
@@ -42,6 +42,27 @@ body {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.login-divider {
|
||||
text-align: center;
|
||||
color: #8b949e;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.oidc-button {
|
||||
display: block;
|
||||
text-align: center;
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #30363d;
|
||||
background: #0d1117;
|
||||
color: #e6edf3;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.oidc-button:hover {
|
||||
border-color: #58a6ff;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #e5484d;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import { useState } from "react";
|
||||
import { login } from "../api";
|
||||
import { useEffect, useState } from "react";
|
||||
import { login, getAuthConfig } from "../api";
|
||||
|
||||
export function Login({ onLoggedIn }: { onLoggedIn: () => void }) {
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [oidcEnabled, setOidcEnabled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
getAuthConfig()
|
||||
.then((c) => setOidcEnabled(c.oidcEnabled))
|
||||
.catch(() => setOidcEnabled(false));
|
||||
}, []);
|
||||
|
||||
async function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
@@ -42,6 +49,14 @@ export function Login({ onLoggedIn }: { onLoggedIn: () => void }) {
|
||||
<button type="submit" disabled={submitting}>
|
||||
{submitting ? "Signing in…" : "Sign in"}
|
||||
</button>
|
||||
{oidcEnabled && (
|
||||
<>
|
||||
<div className="login-divider">or</div>
|
||||
<a className="oidc-button" href="/api/auth/oidc/login">
|
||||
Sign in with Authentik
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user