feat: implement OAuth 2.0 / OpenID Connect support
Some checks failed
Build & Push Docker Image / build (push) Failing after 1m12s
Some checks failed
Build & Push Docker Image / build (push) Failing after 1m12s
- Added OAuth configuration management in the admin panel. - Implemented OAuth authorization flow with PKCE for enhanced security. - Created routes for handling OAuth provider discovery, authorization, and callback. - Integrated OAuth login and registration options in the frontend. - Updated UI components to support OAuth login and registration. - Added internationalization strings for OAuth-related messages. - Implemented encryption for client secrets and secure state management. - Added error handling and user feedback for OAuth processes.
This commit is contained in:
75
src/pages/OAuthCallback.jsx
Normal file
75
src/pages/OAuthCallback.jsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
import { useLanguage } from '../contexts/LanguageContext';
|
||||
import { Loader2, AlertTriangle } from 'lucide-react';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
export default function OAuthCallback() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const [error, setError] = useState(null);
|
||||
const { loginWithOAuth } = useAuth();
|
||||
const { t } = useLanguage();
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
const token = searchParams.get('token');
|
||||
const errorMsg = searchParams.get('error');
|
||||
const returnTo = searchParams.get('return_to') || '/dashboard';
|
||||
|
||||
if (errorMsg) {
|
||||
setError(errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
setError(t('auth.oauthNoToken'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Store token and redirect
|
||||
loginWithOAuth(token)
|
||||
.then(() => {
|
||||
toast.success(t('auth.loginSuccess'));
|
||||
navigate(returnTo, { replace: true });
|
||||
})
|
||||
.catch(() => {
|
||||
setError(t('auth.oauthLoginFailed'));
|
||||
});
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center p-6">
|
||||
<div className="absolute inset-0 bg-th-bg" />
|
||||
<div className="relative w-full max-w-md">
|
||||
<div className="card p-8 backdrop-blur-xl bg-th-card/80 border border-th-border shadow-2xl rounded-2xl text-center">
|
||||
<div className="flex justify-center mb-4">
|
||||
<div className="w-12 h-12 bg-red-500/20 rounded-full flex items-center justify-center">
|
||||
<AlertTriangle size={24} className="text-red-400" />
|
||||
</div>
|
||||
</div>
|
||||
<h2 className="text-xl font-bold text-th-text mb-2">{t('auth.oauthError')}</h2>
|
||||
<p className="text-th-text-s mb-6">{error}</p>
|
||||
<button
|
||||
onClick={() => navigate('/login', { replace: true })}
|
||||
className="btn-primary w-full py-3"
|
||||
>
|
||||
{t('auth.backToLogin')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center p-6">
|
||||
<div className="absolute inset-0 bg-th-bg" />
|
||||
<div className="relative flex flex-col items-center gap-4">
|
||||
<Loader2 size={32} className="animate-spin text-th-accent" />
|
||||
<p className="text-th-text-s">{t('auth.oauthRedirecting')}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user