feat(auth): PKCE flow preparation + CallbackPage dual-mode
All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 29s
All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 29s
- Add oauth.ts — PKCE helpers (code verifier/challenge, token exchange) - Add LoginButton — "Se connecter avec SuperOAuth" component - Update CallbackPage — handles both PKCE (?code) and legacy (?token) flows - Update .env.example — VITE_OAUTH_URL + VITE_OAUTH_CLIENT_ID PKCE flow ready for when SuperOAuth exposes /oauth/authorize endpoint. Legacy flow (redirect + token query param) remains active in production.
This commit is contained in:
39
frontend/src/components/auth/LoginButton.tsx
Normal file
39
frontend/src/components/auth/LoginButton.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { useState } from 'react';
|
||||
import { buildAuthUrl, saveVerifier } from '../../lib/oauth';
|
||||
|
||||
interface LoginButtonProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function LoginButton({ className }: LoginButtonProps) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
async function handleClick() {
|
||||
if (loading) return;
|
||||
setLoading(true);
|
||||
try {
|
||||
const redirectUri = `${window.location.origin}/callback`;
|
||||
const { url, verifier } = await buildAuthUrl(redirectUri);
|
||||
saveVerifier(verifier);
|
||||
window.location.href = url;
|
||||
} catch {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={handleClick}
|
||||
disabled={loading}
|
||||
className={[
|
||||
'rounded border border-[#c9a84c] px-4 py-2 font-mono text-xs text-[#c9a84c]',
|
||||
'transition-all duration-150',
|
||||
'hover:bg-[#c9a84c] hover:text-od-bg',
|
||||
'disabled:opacity-40 disabled:cursor-not-allowed',
|
||||
className ?? '',
|
||||
].join(' ')}
|
||||
>
|
||||
{loading ? '…' : 'Se connecter avec SuperOAuth'}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user