The @authdog/javascript SDK is a framework-agnostic browser client. It handles the OIDC redirect, token storage, sign-in and sign-out, and user resolution with no framework dependency.
@authdog/javascript is not yet published to npm (npm view @authdog/javascript returns 404 at the time of writing). Version 0.1.0 is set to publish publicly from the web-sdk repository, so install it from there until it lands on the registry.
Install
npm install @authdog/javascriptyarn add @authdog/javascriptpnpm add @authdog/javascriptbun add @authdog/javascriptdeno add npm:@authdog/javascriptNo peer dependencies. It works in any browser bundle. Use your environment's public key (pk_...); it is safe to expose to the browser.
Create the client
createAuthdogClient validates the public key once and throws immediately if it is missing, malformed, or points at an untrusted identity host:
import { createAuthdogClient } from "@authdog/javascript"
const authdog = createAuthdogClient({
publicKey: "pk_...",
// storageKey: "token", // optional localStorage key override
})
// On the page the identity provider redirects back to, consume the token.
authdog.handleRedirectCallback()
const render = async () => {
if (authdog.isAuthenticated()) {
const user = await authdog.getUser()
console.log("signed in as", user)
}
}
render()
signinButton.onclick = () => authdog.signIn()
signupButton.onclick = () => authdog.signUp()
signoutButton.onclick = () => authdog.signOut("/")
// React to token changes in this tab and other tabs.
const unsubscribe = authdog.subscribe(() => render())Client methods
| Method | Behaviour |
|---|---|
handleRedirectCallback() |
Reads ?token= from the URL, always strips it, and stores it in localStorage only if JWT-shaped. Returns the token or null. No-op without a token, so call it on every load |
signIn(redirectUri?) |
Redirects to the OIDC authorize flow. redirectUri defaults to window.location.origin |
signUp(redirectUri?) |
Same as signIn, with prompt=signup |
signOut(redirectTo?) |
Clears the stored token and navigates to redirectTo if given |
getUser() |
Calls the OIDC userinfo endpoint with the stored token. Returns the user, or null if unauthenticated or rejected. Never throws |
getToken() |
The stored token, or null |
isAuthenticated() |
Whether a token is present. Presence only |
subscribe(listener) |
Calls listener(token) on token changes in this tab (custom authdog:token-updated event) and other tabs (storage event). Returns an unsubscribe function |
getSigninUrl() |
The hosted sign-in URL, for use as a plain link target |
getPublicKeyPayload() / getPublicKey() |
The parsed public-key payload as an object / as a JSON string |
The default storage key is token. The JWT_PATTERN check is a shape test only. It is not signature, issuer, audience, or expiry validation.
Billing
The client also exposes authdog.billing: listPlans({ for? }) (no auth required), getSubscription(), createSubscription({ planId, planPeriod? }) (returns a Stripe PaymentIntent client secret), and cancelSubscription(). Authenticated calls return null or false when there is no token or the request fails.
Other exports
buildAuthorizeUrl, buildSigninUrl, getTokenFromUri, isJwtShaped, getPublicKeyPayload, TOKEN_STORAGE_KEY, TOKEN_UPDATED_EVENT, and JWT_PATTERN are exported for custom flows.
Caveats
- The token lives in
localStorage. This suits public-client SPA flows. For server-rendered apps that can hold an HttpOnly cookie, use a server-side framework SDK. isAuthenticated()is a UI hint. Validate the bearer token with a backend SDK and enforce authorization on every protected operation server-side.- Outside a browser (no
window), the client returnsnullor does nothing instead of throwing.
Next steps
- Sign up & sign in: the flows behind the redirect.
- Backend requests: validate sessions on your API.