This guide splits those two layers, then says what each Authdog package actually checks, so you do not treat a client hook as a security boundary.
Prerequisites
- An Authdog environment and its publishable public key, the
pk_...value. - The framework package you picked from the SDK catalog in this repository.
- A callback URL registered on that same environment.
- A server path for every operation that touches data. If the only check is in the browser, it is not protected.
The catalog covers Next.js, React Elements, Remix, React Native and Expo, SvelteKit, TanStack Start, Vue, Angular, Astro, Gatsby, and RedwoodJS. React Elements draws UI. It does not integrate a session. Use React components for the widgets, and this page for the boundary.
Implementation
Put the integration in two places, and do not let them share a job.
The client receives the callback, strips tokens out of the query string, and decides what to render. Anyone who can call your API without a browser walks past it. The server validates a cookie or a bearer token with the helper that package documents, then applies authorization. Every protected route lives here.
Next.js App Router. @authdog/nextjs-app gives the client AuthdogProvider, useUser, and useAuth. The provider's callback check only looks at shape: three segments that look like a JWT. It does not check the signature or the expiry. On the server, useAuthMiddleware(publicKey) validates the callback through userinfo and writes HttpOnly cookies:
import { useAuthMiddleware } from "@authdog/nextjs-app/server"
export default useAuthMiddleware(process.env.PK_AUTHDOG!)That middleware exchanges the callback. It does not guard later requests, and it does not re-validate the cookie on the next navigation. Route Handlers and Server Actions that touch data still need their own validation. After the callback works, call a protected handler with no cookie and confirm it fails.
Remix. identityLoader() validates the callback and the cookie through userinfo. It returns { user, isAuthenticated, signinUri } and does not redirect for you. In each protected loader, branch on isAuthenticated. A loader that forgets the check will render the private page for an anonymous request.
Everywhere else, read the helper before you trust the flag. Angular's route guard and Expo's deep-link check are there so the UI can react. They are not cryptographic validation. In SvelteKit, locals.authdog.isAuthenticated means a cookie is present. Call getUser(request) when you need to know the token is good. Vue's getSession() result is raw input. Treat it as untrusted until something on the server has checked it. Gatsby and Redwood ship a server requireAuth that validates through userinfo. Use that on the server path. Astro's validating call is createAuthdogServer().getUser().
If you are unsure which function validates, assume the one that is easy to call from a component does not.
Security considerations
- The publishable public key may ship to the client. Confidential credentials stay on the server.
- Strip the callback token from the URL after you process it. Removing it, or checking that it has three segments, is not verification.
- A cookie existing is not a cookie being valid. Validate on the server before you return data.
- A validated identity still needs a role, a permission, or an organization check. Authentication got you a user. Authorization decides the action.
- Logout often has to clear both browser storage and the server cookie. Follow the helper for the package you installed, then call a protected route and expect a failure.
Validation checklist
- Client and server use configuration for the same Authdog environment.
- Callback token is validated before a trusted cookie is created.
- Protected server operation validates credentials on every request.
- Browser route guards and identity hooks are treated as UX only.
- Authorization runs after successful authentication.
- Logout clears every storage location used by the selected SDK.
Troubleshooting
The UI says you are signed in and the API returns 401. The client saw a token-shaped value. Confirm the server received the cookie or the bearer header, and that it called the helper which hits userinfo. A hook that only reads local storage will disagree with the API forever.
The callback succeeds and the next request is anonymous. The callback response did not include every Set-Cookie, or the cookie's scope does not cover the host you are calling. Compare the set-cookie attributes with the deployment URL.
The server sees a cookie and still should not let the request through. Some middleware only records that a cookie exists. Swap it for the userinfo-backed method the package documents, and test again with a garbage cookie. A present-but-invalid cookie must fail.
Next steps
- Open the package you installed under Framework integrations.
- Read Sessions and tokens for how the credential is delivered and checked.
- Read Backend requests for the enforcement pattern.
- Add Authorization after the identity check is real.