一键导入
oidc-hosted-page-react
Implement "Sign in with SSO" in React SPA applications using SSOJet OIDC with PKCE.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Implement "Sign in with SSO" in React SPA applications using SSOJet OIDC with PKCE.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Implement Machine-to-Machine (M2M) authentication using SSOJet OAuth2 Client Credentials flow for backend services and daemons.
Implement "Sign in with SSO" in native Android/Kotlin applications using SSOJet OIDC with AppAuth.
Implement "Sign in with SSO" in Angular SPA applications using SSOJet OIDC with PKCE.
Implement "Sign in with SSO" in ASP.NET Core applications using SSOJet OIDC middleware.
Implement "Sign in with SSO" in Go applications using SSOJet OIDC Authorization Code flow.
Implement "Sign in with SSO" in native iOS/Swift applications using SSOJet OIDC with AppAuth.
| name | oidc-hosted-page-react |
| description | Implement "Sign in with SSO" in React SPA applications using SSOJet OIDC with PKCE. |
This expert AI assistant guide walks you through integrating "Sign in with SSO" functionality into an existing login page in a React application using SSOJet as an OIDC identity provider. The goal is to modify the existing login flow to add SSO support without disrupting the current traditional login functionality (e.g., email/password).
oidc-client-ts, react-oidc-context.http://localhost:5173/auth/callback).Note: For SPAs, the recommended flow is Authorization Code with PKCE (no Client Secret required on the front-end).
Run the following command to install the required libraries:
npm install oidc-client-ts react-oidc-context react-router-dom
Create a dedicated configuration file (e.g., src/lib/oidcConfig.ts):
// src/lib/oidcConfig.ts
import { WebStorageStateStore } from 'oidc-client-ts';
export const oidcConfig = {
authority: 'https://auth.ssojet.com', // Your SSOJet Issuer URL
client_id: 'your_client_id',
redirect_uri: 'http://localhost:5173/auth/callback',
post_logout_redirect_uri: 'http://localhost:5173/login',
response_type: 'code',
scope: 'openid profile email',
userStore: new WebStorageStateStore({ store: window.localStorage }),
};
Update your src/main.tsx to wrap the application with the OIDC provider:
// src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { AuthProvider } from 'react-oidc-context';
import { oidcConfig } from './lib/oidcConfig';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<AuthProvider {...oidcConfig}>
<BrowserRouter>
<App />
</BrowserRouter>
</AuthProvider>
</React.StrictMode>
);
Modify your existing login component (e.g., src/pages/Login.tsx) to include the "Sign in with SSO" toggle:
// src/pages/Login.tsx
import { useState } from 'react';
import { useAuth } from 'react-oidc-context';
export default function LoginPage() {
const [isSSO, setIsSSO] = useState(false);
const [email, setEmail] = useState('');
const auth = useAuth();
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
if (isSSO) {
// Trigger SSO login via the OIDC library with login_hint
auth.signinRedirect({
extraQueryParams: { login_hint: email },
});
} else {
// Existing password login logic here
console.log('Processing traditional login...');
}
};
return (
<div className="login-container">
<h1>Sign In</h1>
<form onSubmit={handleLogin}>
<div>
<label htmlFor="email">Email</label>
<input
type="email"
id="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
{!isSSO && (
<div>
<label htmlFor="password">Password</label>
<input type="password" id="password" required />
</div>
)}
<button type="submit">
{isSSO ? 'Continue with SSO' : 'Sign In'}
</button>
</form>
<button type="button" onClick={() => setIsSSO(!isSSO)}>
{isSSO ? 'Back to Password Login' : 'Sign in with SSO'}
</button>
</div>
);
}
Create a callback component to handle the OIDC redirect (e.g., src/pages/AuthCallback.tsx):
// src/pages/AuthCallback.tsx
import { useEffect } from 'react';
import { useAuth } from 'react-oidc-context';
import { useNavigate } from 'react-router-dom';
export default function AuthCallback() {
const auth = useAuth();
const navigate = useNavigate();
useEffect(() => {
if (auth.isAuthenticated) {
console.log('Authenticated User:', auth.user?.profile);
navigate('/dashboard');
}
if (auth.error) {
console.error('OIDC Callback Error:', auth.error);
navigate('/login?error=oidc_failed');
}
}, [auth.isAuthenticated, auth.error, navigate]);
if (auth.isLoading) {
return <p>Authenticating...</p>;
}
return null;
}
Update your src/App.tsx to include the callback route:
// src/App.tsx
import { Routes, Route } from 'react-router-dom';
import LoginPage from './pages/Login';
import AuthCallback from './pages/AuthCallback';
import Dashboard from './pages/Dashboard';
export default function App() {
return (
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/auth/callback" element={<AuthCallback />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/" element={<LoginPage />} />
</Routes>
);
}
Dashboard Page (src/pages/Dashboard.tsx):
// src/pages/Dashboard.tsx
import { useAuth } from 'react-oidc-context';
import { Navigate } from 'react-router-dom';
export default function Dashboard() {
const auth = useAuth();
if (!auth.isAuthenticated) {
return <Navigate to="/login" />;
}
return (
<div>
<h1>Dashboard</h1>
<pre>{JSON.stringify(auth.user?.profile, null, 2)}</pre>
<button onClick={() => auth.signoutRedirect()}>Logout</button>
</div>
);
}
npm run dev.http://localhost:5173/login)./auth/callback and then to /dashboard.auth.error from the useAuth hook to display OIDC-specific errors in the UI.oidc-client-ts. Never store a Client Secret in the front-end.auth.isAuthenticated before rendering child routes.