- useAuthConfig fetches public /auth/config; LoginPage hides the password form when oidc_only and shows an SSO button when enabled. - /oidc/callback route applies the returned JWT (sign-in) or shows the link result; oidc_error surfaced on LoginPage. - UsersPage: hides password fields in OIDC-only mode; admin OIDC bind/unbind UI per user. Sidebar self-service "Link OIDC account" (non-OIDC_ONLY). - Dockerfile ARG/ENV HARBORFORGE_OIDC_ONLY. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
60 lines
1.6 KiB
TypeScript
60 lines
1.6 KiB
TypeScript
import { useState, useEffect, useCallback } from 'react'
|
|
import api from '@/services/api'
|
|
import type { User } from '@/types'
|
|
|
|
interface AuthState {
|
|
user: User | null
|
|
token: string | null
|
|
loading: boolean
|
|
}
|
|
|
|
export function useAuth() {
|
|
const [state, setState] = useState<AuthState>({
|
|
user: null,
|
|
token: localStorage.getItem('token'),
|
|
loading: true,
|
|
})
|
|
|
|
const fetchUser = useCallback(async () => {
|
|
const token = localStorage.getItem('token')
|
|
if (!token) {
|
|
setState({ user: null, token: null, loading: false })
|
|
return
|
|
}
|
|
try {
|
|
const { data } = await api.get<User>('/auth/me')
|
|
setState({ user: data, token, loading: false })
|
|
} catch {
|
|
localStorage.removeItem('token')
|
|
setState({ user: null, token: null, loading: false })
|
|
}
|
|
}, [])
|
|
|
|
useEffect(() => { fetchUser() }, [fetchUser])
|
|
|
|
const login = async (username: string, password: string) => {
|
|
const form = new URLSearchParams()
|
|
form.append('username', username)
|
|
form.append('password', password)
|
|
const { data } = await api.post('/auth/token', form, {
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
})
|
|
localStorage.setItem('token', data.access_token)
|
|
setState((s) => ({ ...s, token: data.access_token }))
|
|
await fetchUser()
|
|
}
|
|
|
|
const loginWithToken = async (token: string) => {
|
|
localStorage.setItem('token', token)
|
|
setState((s) => ({ ...s, token }))
|
|
await fetchUser()
|
|
}
|
|
|
|
const logout = () => {
|
|
localStorage.removeItem('token')
|
|
setState({ user: null, token: null, loading: false })
|
|
}
|
|
|
|
return { ...state, login, loginWithToken, logout }
|
|
}
|