a a vibe-coded abomination experiment of a fragrance review platform built on the atmosphere.
drydown.social
1import { BrowserOAuthClient } from '@atproto/oauth-client-browser'
2import { oauthConfig } from './config'
3
4// The metadata must match what is served at the client_id URL
5// For local development, we use BrowserOAuthClient.load which handles loopback metadata generation
6
7let client: BrowserOAuthClient | undefined
8
9export async function getClient() {
10 if (client) return client
11
12 console.log('Environment:', { isDev: import.meta.env.DEV, clientId: oauthConfig.clientId })
13
14 try {
15 client = await BrowserOAuthClient.load({
16 clientId: oauthConfig.clientId,
17 handleResolver: 'https://bsky.social',
18 fetch: window.fetch.bind(window), // Fix for "Illegal invocation" in Safari/Strict mode
19 })
20 return client
21 } catch (err) {
22 console.error('Failed to initialize OAuth client:', err)
23 throw err
24 }
25}
26
27export async function initAuth() {
28 console.log('Initializing Auth...')
29 const c = await getClient()
30 const result = await c.init()
31 return result
32}
33
34export async function login(handle: string) {
35 const c = await getClient()
36
37 // Explicitly use the first redirect_uri from the active configuration
38 const redirectUri = oauthConfig.redirectUri
39
40 return await c.signIn(handle, {
41 state: undefined,
42 prompt: 'login',
43 redirect_uri: redirectUri as any,
44 })
45}
46
47export async function logout(sessionDid: string) {
48 const c = await getClient()
49 // Revoke the session to clear it from storage
50 await c.revoke(sessionDid)
51}