JavaScript SDK
Two packages. The core does the protocol and depends on nothing; the React package is a thin bridge to component state.
npm install @elchi/eauth-react
React
import {
EAuthProvider, SignedIn, SignedOut, SignInButton, useEAuth,
} from "@elchi/eauth-react";
export default function App() {
return (
<EAuthProvider clientId="eauth_pub_..." redirectUri={location.origin + "/"}>
<SignedOut><SignInButton /></SignedOut>
<SignedIn><Profile /></SignedIn>
</EAuthProvider>
);
}
function Profile() {
const { user, signOut } = useEAuth();
return (
<>
<p>Hello {user.name}</p>
<button onClick={() => signOut()}>Sign out</button>
</>
);
}
That is the whole integration. The provider handles the redirect on load, verifies the response, and keeps the session refreshed.
Calling your own API
const { getAccessToken } = useEAuth();
const response = await fetch("/api/orders", {
headers: { Authorization: `Bearer ${await getAccessToken()}` },
});
getAccessToken refreshes when the current token is close to expiring, so you
never have to check yourself.
Without a framework
import { EAuth } from "@elchi/eauth";
const auth = new EAuth({
clientId: "eauth_pub_...",
redirectUri: location.origin + "/",
});
// Safe on every load: returns null when the URL carries no response.
const user = await auth.handleRedirect() ?? auth.getUser();
if (!user) await auth.signIn();
What the SDK does that a tutorial would not
No client secret anywhere. A browser cannot keep one. If you want to pass one, the client is registered as the wrong type.
Tokens in memory by default. A token in localStorage is readable by any
script on the page, so one cross-site scripting bug in any dependency hands
over the session. The default keeps tokens in a closure and signs the user in
again silently after a reload. storage: "local" is available once you have
accepted that trade.
state, nonce and iss are all verified, and a mismatch throws rather
than warns. These are the three checks integrations most often skip. The iss
check is RFC 9207 and is what stops a mix-up attack when your application talks
to more than one provider.
One refresh at a time. Concurrent callers share a single refresh. Without that, five components mounting at once each start their own, and because refresh tokens rotate, four of them present a token that has already been rotated. The server correctly reads that as a stolen token and revokes the whole chain, signing your user out for no reason.
Errors
Everything throws EAuthError with a code you can branch on.
| Code | Meaning |
|---|---|
state_mismatch |
The response did not come from a sign-in started in this browser |
issuer_mismatch |
The response or token came from a different server |
nonce_mismatch |
The ID token belongs to a different sign-in |
no_pending_request |
The redirect was opened in a different tab |
pkce_unsupported |
The server does not advertise S256 |
Self-hosting
Pass issuer pointing at your own deployment. Everything else is discovered
from /.well-known/openid-configuration, so no other URL is hardcoded.