modern-auth
v2.0.0
Published
React OIDC Authorization Code + PKCE authentication
Readme
modern-auth
React authentication for OAuth 2.0 / OIDC.
Version lines
| Version | Flow | Who should use it |
|---|---|---|
| 2.x (latest) | Authorization Code + PKCE (S256). Public client_id only. No secret. | New apps and apps migrating off secrets |
| 1.x (legacy tag) | Existing client_id + client_secret behavior (same as 0.2.30) | Apps that cannot move to PKCE yet |
| 0.2.x | Same secret-based flow as 1.x | Apps already pinned to ^0.2.29 — they stay there automatically |
A fresh npm install modern-auth installs 2.x (PKCE).
Existing ^0.2.29 / ^0.2.30 installs do not jump to 1.x or 2.x (<0.3.0).
Install
New app / PKCE (default):
npm install modern-auth
# same as: npm install modern-auth@^2Stay on client_id + client_secret (do not take 2.x):
# preferred: stay on the 1.x legacy line
npm install modern-auth@^1.0.0
# or keep the original 0.2 pin (no change needed)
npm install [email protected]{
"dependencies": {
"modern-auth": "^1.0.0"
}
}antd is a peer dependency of 2.x (Login UI). Install it with PKCE apps:
npm install modern-auth@^2 antdSee MIGRATION.md to move from 1.x (or 0.2.x) to 2.x.
Publishing (maintainers)
Publish 1.x first from the last secret-based source (0.2.30), then 2.x so latest is PKCE.
# 1) On a checkout of 0.2.30 — secret-based API, version 1.0.0
# package.json version: 1.0.0
npm publish --tag legacy
npm dist-tag add [email protected] legacy
# 2) On this PKCE branch — version 2.0.0
npm publish
# latest → 2.0.0 (fresh npm install modern-auth)Confirm:
npm dist-tag ls modern-auth
# latest = 2.0.0 (PKCE)
# legacy = 1.0.0 (client_id + client_secret)If latest accidentally points at 1.x:
npm dist-tag add [email protected] latest| Consumer range | npm update result |
|---|---|
| ^0.2.29 | Stays on 0.2.x |
| ^1.0.0 | Stays on 1.x (secret). Never 2.x |
| ^2.0.0 or no range (npm install modern-auth) | 2.x PKCE |
PKCE usage (2.x)
Register the exact callback URL with the OIDC provider, including scheme, host, port, and path.
import { ModernAuth, Login, useAuth } from 'modern-auth'
import { BrowserRouter } from 'react-router-dom'
const oidcConfig = {
authority: 'https://identity.example.com/oidc',
client_id: 'dataos_public',
redirect_uri: `${window.location.origin}/auth/callback`,
scope: 'openid profile email groups federated:id offline_access',
loadUserInfo: true,
automaticSilentRenew: true,
}
function ProtectedApp() {
const auth = useAuth()
if (auth.isLoading) return null
if (!auth.isAuthenticated) {
return <Login logo="/logo.svg" message={null} />
}
return <App />
}
export default function Root() {
return (
<BrowserRouter>
<ModernAuth oidc_config={oidcConfig}>
<ProtectedApp />
</ModernAuth>
</BrowserRouter>
)
}2.x forces:
{
response_type: 'code',
disablePKCE: false
}oidc-client-ts generates the verifier and sends an S256 code challenge. Supplying client_secret, another response type, or disablePKCE: true throws.
Runtime configuration (app-owned)
2.x does not define /api/config. The app may load public settings before rendering ModernAuth:
{
"authority": "https://identity.example.com/oidc",
"client_id": "dataos_public",
"redirect_uri": "https://app.example.com/auth/callback",
"scope": "openid profile email"
}Do not return client_secret for a 2.x browser app. A 1.x app may still return a secret if it has not migrated.
