Overview
The@atproto/oauth-client-browser package provides a complete OAuth client implementation specifically designed for browser-based Single Page Applications (SPAs). It uses WebCrypto for cryptographic operations and IndexedDB for persistent storage.
This package is optimized for client-side applications without a backend server. For applications with a backend, consider using
@atproto/oauth-client-node on the server side for enhanced security.Installation
Requirements
- Modern browser with WebCrypto API support
- HTTPS connection (required for WebCrypto)
- IndexedDB support
- ECMAScript 2020+ features
Quick Start
BrowserOAuthClient Class
Static Methods
load
string
required
The client ID URL. Must be either:
https://URL for discoverable clients (fetches metadata)http://127.0.0.1orhttp://[::1]for loopback clients (development)
string | URL | HandleResolver
Service URL for resolving AT Protocol handles. Commonly
'https://bsky.social'.'query' | 'fragment'
default:"'fragment'"
How OAuth responses are returned:
fragment: Parameters in URL fragment (safer, not sent to server)query: Parameters in URL query string
string
PLC directory URL for DID resolution. Defaults to
'https://plc.directory'.AbortSignal
Signal to cancel metadata loading.
Constructor
OAuthClientMetadataInput
Client metadata object. If omitted, uses loopback client metadata based on current origin.
'query' | 'fragment'
default:"'fragment'"
OAuth response mode.
string | URL | HandleResolver
Handle resolver service.
string
PLC directory URL.
Fetch
Custom fetch implementation.
Instance Methods
init
- Checks URL for OAuth callback parameters
- Processes callback if present
- Restores the last active session if available
OAuthSession
The authenticated session.
string
The application state from authorization (only present on callbacks).
Returned when no session is available.
signIn
string
required
User’s handle (e.g.,
alice.bsky.social) or DID.string
Application state to preserve.
'none' | 'login' | 'consent'
Authorization prompt behavior:
none: Silent sign-in (SSO)login: Force re-authenticationconsent: Force re-consent
string
OAuth scopes to request.
string
Preferred UI languages (e.g.,
'fr-CA fr en').AbortSignal
Signal to cancel authorization.
signInCallback
init() instead).
URLSearchParams
URL parameters. Defaults to current page’s URL parameters.
string
The redirect URI used in authorization.
OAuthSession
The authenticated session.
string
The application state.
restore
string
required
The user’s DID.
boolean | 'auto'
default:"'auto'"
Token refresh behavior:
'auto': Refresh if expired (recommended)true: Force refreshfalse: Use cached tokens
OAuthSession
The restored session.
TokenRefreshErrorif session cannot be refreshedTokenRevokedErrorif session was revoked
getSession
string
required
The user’s DID.
OAuthSession
The session if available.
If no session exists for this DID.
revoke
string
required
The user’s DID to revoke.
Properties
ClientMetadata
The client metadata being used.
OAuthResponseMode
The configured response mode.
Session Management
The browser client automatically manages sessions using IndexedDB:Automatic Storage
- Sessions persist across page reloads
- Tokens refresh automatically when expired
- DPoP keys stored securely in IndexedDB
- Cross-tab synchronization using BroadcastChannel
Multi-Tab Support
Monitoring Sessions
OAuth Session Usage
TheOAuthSession returned by the client can be used directly:
With @atproto/api
Direct API Calls
Development Setup
Loopback Client (localhost)
For local development without deploying client metadata:- Origin must be
http://127.0.0.1:<port>orhttp://[::1]:<port> - Cannot use
http://localhost:<port>(browser security) - Limited features: no custom branding, shorter token lifetime
Production Setup
For production, host your client metadata: 1. Createclient-metadata.json:
Complete Example
React Application
Vanilla JavaScript
Error Handling
Security Considerations
WebCrypto Key Storage
DPoP keys are stored in IndexedDB as non-extractable CryptoKeys:Storage Security
- IndexedDB: Encrypted at rest by browser
- Same-origin policy: Data only accessible by your origin
- No localStorage: Tokens not exposed to JavaScript string access
- Cross-tab sync: Uses BroadcastChannel (same-origin only)
HTTPS Requirement
Token Lifecycle
- Access tokens refresh automatically before expiration
- Refresh tokens stored encrypted in IndexedDB
- Sessions auto-deleted on server-side revocation
- Stale sessions cleaned up on init
Browser Compatibility
Required APIs
- ✓ WebCrypto API (crypto.subtle)
- ✓ IndexedDB
- ✓ BroadcastChannel (optional, for multi-tab)
- ✓ Web Locks API (optional, for concurrent refresh prevention)
- ✓ ECMAScript 2020 features
Supported Browsers
- Chrome 87+
- Firefox 78+
- Safari 14+
- Edge 88+
Polyfills
No polyfills required for modern browsers. Older browsers may need:Utility Functions
buildLoopbackClientId
Related Packages
@atproto/oauth-client
Core OAuth client (platform-agnostic)
@atproto/oauth-client-node
Node.js OAuth client for backend apps
@atproto/api
High-level AT Protocol API
@atproto/crypto
Cryptographic operations and key management