Skip to content

Overview

HappyView provides JavaScript packages for building third-party apps that authenticate with a HappyView instance and make XRPC requests on behalf of users.

PackagePurpose
@happyview/lex-agentRecommended: type-safe XRPC via @atproto/lex Client with HappyView DPoP auth
@happyview/oauth-clientPlatform-agnostic core: DPoP key provisioning, session management, authenticated fetch
@happyview/oauth-client-browserBrowser OAuth client whose API matches @atproto/oauth-client-browser
@happyview/oauth-client-nodeNode.js OAuth client for server-side apps, matching @atproto/oauth-client-node

Starting a new app? Use @happyview/lex-agent with @atproto/lex. It gives you type-safe XRPC calls through a Client that routes requests to your HappyView instance with DPoP authentication.

Already using @atproto/api? HappyViewSession works directly as a session manager for @atproto/api’s Agent: pass it to new Agent(session). See Using with @atproto/api.

Already using @atproto/oauth-client-browser? Switch to @happyview/oauth-client-browser. Its HappyViewBrowserClient has the same shape of API, and runs the atproto OAuth flow itself with HappyView’s DPoP key provisioning and session registration added.

Building a server-side (Node.js) app? Use @happyview/oauth-client-node. It handles handle resolution, DID resolution, PDS discovery, and the full OAuth flow server-side. Matches the API surface of @atproto/oauth-client-node.

Building something more custom? Use @happyview/oauth-client directly and provide your own StorageAdapter.

Third-party apps authenticate using HappyView’s DPoP key provisioning flow:

  1. The SDK requests a DPoP keypair from the HappyView instance.
  2. Your app runs a standard atproto OAuth flow with the user’s PDS using that keypair.
  3. The SDK registers the resulting tokens with HappyView.
  4. All subsequent XRPC requests are authenticated with DPoP proofs. HappyView handles its own lexicons locally and passes any other method to its XRPC proxy, which forwards it to the user’s PDS as the user only when the instance’s proxy routing is serviceproxy.

If your app is a confidential atproto OAuth client, step 2 also needs a signed private_key_jwt assertion for its PAR and token-exchange requests. @happyview/oauth-client’s getClientAssertion() mints one. See Client assertions.

Terminal window
npm install @happyview/lex-agent @happyview/oauth-client-browser @atproto/lex
import { Client } from "@atproto/lex";
import { HappyViewBrowserClient } from "@happyview/oauth-client-browser";
import { createAgent } from "@happyview/lex-agent";
// Set up the OAuth client
const oauthClient = new HappyViewBrowserClient({
instanceUrl: "https://happyview.example.com",
clientId: "https://example.com/oauth-client-metadata.json",
clientKey: "hvc_your_client_key",
});
// Sign in: redirects to the user's PDS
await oauthClient.signIn("alice.bsky.social");
// On page load: restore session or process callback
const result = await oauthClient.init();
const session = result?.session;
if (!session) throw new Error("Not signed in");
// Create a type-safe Lex client
const agent = createAgent(session);
const lex = new Client(agent);
// Make type-safe XRPC calls
const game = await lex.xrpc(myLexicons.com.example.getGame, {
params: { slug: "celeste" },
});