feat(auth): remove center api key from frontend login flow
This commit is contained in:
@@ -13,15 +13,15 @@ export function AuthProvider({ children }: PropsWithChildren) {
|
|||||||
() => ({
|
() => ({
|
||||||
session,
|
session,
|
||||||
isAuthed: !!session,
|
isAuthed: !!session,
|
||||||
login: async (centerApiBase: string, centerApiKey: string, email: string, password: string) => {
|
login: async (centerApiBase: string, email: string, password: string) => {
|
||||||
const next = await loginCenter(centerApiBase, centerApiKey, { email, password })
|
const next = await loginCenter(centerApiBase, { email, password })
|
||||||
setAuthSession(next)
|
setAuthSession(next)
|
||||||
setSession(next)
|
setSession(next)
|
||||||
},
|
},
|
||||||
logout: async () => {
|
logout: async () => {
|
||||||
if (session?.refreshToken) {
|
if (session?.refreshToken) {
|
||||||
try {
|
try {
|
||||||
await logoutCenter(session.centerApiBase, session.centerApiKey, session.refreshToken)
|
await logoutCenter(session.centerApiBase, session.refreshToken)
|
||||||
} catch {
|
} catch {
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
@@ -33,12 +33,13 @@ export function AuthProvider({ children }: PropsWithChildren) {
|
|||||||
if (!session) return null
|
if (!session) return null
|
||||||
if (!isAccessTokenStale(session.accessToken)) return session.accessToken
|
if (!isAccessTokenStale(session.accessToken)) return session.accessToken
|
||||||
|
|
||||||
const refreshed = await refreshCenter(session.centerApiBase, session.centerApiKey, session.refreshToken)
|
const refreshed = await refreshCenter(session.centerApiBase, session.refreshToken)
|
||||||
const next: AuthSession = {
|
const next: AuthSession = {
|
||||||
...session,
|
...session,
|
||||||
accessToken: refreshed.accessToken,
|
accessToken: refreshed.accessToken,
|
||||||
refreshToken: refreshed.refreshToken,
|
refreshToken: refreshed.refreshToken,
|
||||||
tokenType: refreshed.tokenType,
|
tokenType: refreshed.tokenType,
|
||||||
|
expiresIn: refreshed.expiresIn,
|
||||||
}
|
}
|
||||||
setAuthSession(next)
|
setAuthSession(next)
|
||||||
setSession(next)
|
setSession(next)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type { AuthSession } from '../lib/auth-storage'
|
|||||||
export type AuthContextValue = {
|
export type AuthContextValue = {
|
||||||
session: AuthSession | null
|
session: AuthSession | null
|
||||||
isAuthed: boolean
|
isAuthed: boolean
|
||||||
login: (centerApiBase: string, centerApiKey: string, email: string, password: string) => Promise<void>
|
login: (centerApiBase: string, email: string, password: string) => Promise<void>
|
||||||
logout: () => Promise<void>
|
logout: () => Promise<void>
|
||||||
ensureFreshToken: () => Promise<string | null>
|
ensureFreshToken: () => Promise<string | null>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
export type AuthSession = {
|
export type AuthSession = {
|
||||||
centerApiBase: string
|
centerApiBase: string
|
||||||
centerApiKey: string
|
|
||||||
accessToken: string
|
accessToken: string
|
||||||
refreshToken: string
|
refreshToken: string
|
||||||
tokenType: string
|
tokenType: string
|
||||||
|
expiresIn?: number
|
||||||
user: {
|
user: {
|
||||||
id: string
|
id: string
|
||||||
email: string
|
email: string
|
||||||
@@ -18,6 +18,7 @@ export type AuthSession = {
|
|||||||
guildNodeId: string
|
guildNodeId: string
|
||||||
token: string
|
token: string
|
||||||
tokenType: string
|
tokenType: string
|
||||||
|
expiresIn?: number
|
||||||
}>
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,22 +4,23 @@ import type { AuthSession } from './auth-storage'
|
|||||||
export type LoginPayload = { email: string; password: string }
|
export type LoginPayload = { email: string; password: string }
|
||||||
|
|
||||||
type LoginResponse = {
|
type LoginResponse = {
|
||||||
centerApiBase: string
|
|
||||||
accessToken: string
|
accessToken: string
|
||||||
refreshToken: string
|
refreshToken: string
|
||||||
tokenType: string
|
tokenType: string
|
||||||
|
expiresIn?: number
|
||||||
user: { id: string; email: string }
|
user: { id: string; email: string }
|
||||||
guilds: Array<{ nodeId: string; name: string; endpoint: string; status: 'active' | 'offline' | 'revoked' }>
|
guilds: Array<{ nodeId: string; name: string; endpoint: string; status: 'active' | 'offline' | 'revoked' }>
|
||||||
guildAccessTokens: Array<{ guildNodeId: string; token: string; tokenType: string }>
|
guildAccessTokens: Array<{ guildNodeId: string; token: string; tokenType: string; expiresIn?: number }>
|
||||||
}
|
}
|
||||||
|
|
||||||
type RefreshResponse = {
|
type RefreshResponse = {
|
||||||
accessToken: string
|
accessToken: string
|
||||||
refreshToken: string
|
refreshToken: string
|
||||||
tokenType: string
|
tokenType: string
|
||||||
|
expiresIn?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
function centerClient(centerApiBase: string, centerApiKey: string) {
|
function centerClient(centerApiBase: string) {
|
||||||
const client = axios.create({
|
const client = axios.create({
|
||||||
baseURL: centerApiBase,
|
baseURL: centerApiBase,
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
@@ -27,7 +28,6 @@ function centerClient(centerApiBase: string, centerApiKey: string) {
|
|||||||
|
|
||||||
client.interceptors.request.use((request) => {
|
client.interceptors.request.use((request) => {
|
||||||
const requestId = crypto.randomUUID()
|
const requestId = crypto.randomUUID()
|
||||||
request.headers['x-api-key'] = centerApiKey
|
|
||||||
request.headers['x-request-id'] = requestId
|
request.headers['x-request-id'] = requestId
|
||||||
request.headers['x-client-name'] = 'fabric-frontend'
|
request.headers['x-client-name'] = 'fabric-frontend'
|
||||||
return request
|
return request
|
||||||
@@ -36,16 +36,16 @@ function centerClient(centerApiBase: string, centerApiKey: string) {
|
|||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loginCenter(centerApiBase: string, centerApiKey: string, payload: LoginPayload): Promise<AuthSession> {
|
export async function loginCenter(centerApiBase: string, payload: LoginPayload): Promise<AuthSession> {
|
||||||
const res = await centerClient(centerApiBase, centerApiKey).post<LoginResponse>('/auth/login', payload)
|
const res = await centerClient(centerApiBase).post<LoginResponse>('/auth/login', payload)
|
||||||
return { ...res.data, centerApiBase, centerApiKey }
|
return { ...res.data, centerApiBase }
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function refreshCenter(centerApiBase: string, centerApiKey: string, refreshToken: string): Promise<RefreshResponse> {
|
export async function refreshCenter(centerApiBase: string, refreshToken: string): Promise<RefreshResponse> {
|
||||||
const res = await centerClient(centerApiBase, centerApiKey).post<RefreshResponse>('/auth/refresh', { refreshToken })
|
const res = await centerClient(centerApiBase).post<RefreshResponse>('/auth/refresh', { refreshToken })
|
||||||
return res.data
|
return res.data
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function logoutCenter(centerApiBase: string, centerApiKey: string, refreshToken: string): Promise<void> {
|
export async function logoutCenter(centerApiBase: string, refreshToken: string): Promise<void> {
|
||||||
await centerClient(centerApiBase, centerApiKey).post('/auth/logout', { refreshToken })
|
await centerClient(centerApiBase).post('/auth/logout', { refreshToken })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ export default function LoginPage() {
|
|||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { login, isAuthed, session } = useAuth()
|
const { login, isAuthed, session } = useAuth()
|
||||||
const [centerApiBase, setCenterApiBase] = useState('http://localhost:7001/api')
|
const [centerApiBase, setCenterApiBase] = useState('http://localhost:7001/api')
|
||||||
const [centerApiKey, setCenterApiKey] = useState('')
|
|
||||||
const [email, setEmail] = useState('')
|
const [email, setEmail] = useState('')
|
||||||
const [password, setPassword] = useState('')
|
const [password, setPassword] = useState('')
|
||||||
const [error, setError] = useState('')
|
const [error, setError] = useState('')
|
||||||
@@ -16,7 +15,7 @@ export default function LoginPage() {
|
|||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setError('')
|
setError('')
|
||||||
try {
|
try {
|
||||||
await login(centerApiBase.trim(), centerApiKey.trim(), email, password)
|
await login(centerApiBase.trim(), email, password)
|
||||||
navigate('/workspace')
|
navigate('/workspace')
|
||||||
} catch {
|
} catch {
|
||||||
setError('Login failed. Please check your email and password.')
|
setError('Login failed. Please check your email and password.')
|
||||||
@@ -34,12 +33,6 @@ export default function LoginPage() {
|
|||||||
onChange={(e) => setCenterApiBase(e.target.value)}
|
onChange={(e) => setCenterApiBase(e.target.value)}
|
||||||
placeholder="Center API Base (e.g. http://localhost:7001/api)"
|
placeholder="Center API Base (e.g. http://localhost:7001/api)"
|
||||||
/>
|
/>
|
||||||
<input
|
|
||||||
className="input"
|
|
||||||
value={centerApiKey}
|
|
||||||
onChange={(e) => setCenterApiKey(e.target.value)}
|
|
||||||
placeholder="Center API Key"
|
|
||||||
/>
|
|
||||||
<input className="input" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" type="email" />
|
<input className="input" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" type="email" />
|
||||||
<input
|
<input
|
||||||
className="input"
|
className="input"
|
||||||
|
|||||||
Reference in New Issue
Block a user