Mirror — see github.com/blacksky-algorithms/blacksky.community
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #76 from blacksky-algorithms/fix/oauth-session-restore

Fix OAuth session restore hangs and false Logged out status

authored by

ruuuuu.de and committed by
GitHub
864fd6b7 7e7ac587

+59 -10
+3 -1
src/components/AccountList.tsx
··· 122 122 onSelect(account) 123 123 }, [account, onSelect]) 124 124 125 - const isLoggedOut = !account.refreshJwt || isJwtExpired(account.refreshJwt) 125 + const isLoggedOut = account.isOauthSession 126 + ? false // OAuth sessions are managed by the OAuth client, not refreshJwt 127 + : !account.refreshJwt || isJwtExpired(account.refreshJwt) 126 128 127 129 return ( 128 130 <Button
+10 -1
src/screens/Login/ChooseAccountForm.tsx
··· 46 46 } 47 47 try { 48 48 setPendingDid(account.did) 49 - await resumeSession(account, true) 49 + await Promise.race([ 50 + resumeSession(account, true), 51 + new Promise<never>((_, reject) => 52 + setTimeout( 53 + () => reject(new Error('Session resume timed out')), 54 + 15_000, 55 + ), 56 + ), 57 + ]) 50 58 ax.metric('account:loggedIn', { 51 59 logContext: 'ChooseAccountForm', 52 60 withPassword: false, ··· 56 64 logger.error('choose account: initSession failed', { 57 65 message: e.message, 58 66 }) 67 + Toast.show(_(msg`Sign in failed. Please try again.`)) 59 68 // Move to login form. 60 69 onSelectAccount(account) 61 70 } finally {
+46 -8
src/state/session/oauth-agent.ts
··· 20 20 return agent.prepare(account, gates, moderation) 21 21 } 22 22 23 + const OAUTH_RESTORE_TIMEOUT_MS = 10_000 24 + 23 25 export async function oauthResumeSession(account: SessionAccount) { 24 26 const client = getWebOAuthClient() 25 - const session = await client.restore(account.did) 27 + let session: OAuthSession 28 + try { 29 + session = await Promise.race([ 30 + client.restore(account.did), 31 + new Promise<never>((_, reject) => 32 + setTimeout( 33 + () => reject(new Error('OAuth session restore timed out')), 34 + OAUTH_RESTORE_TIMEOUT_MS, 35 + ), 36 + ), 37 + ]) 38 + } catch (e) { 39 + logger.error('oauthResumeSession: restore failed', { 40 + did: account.did, 41 + error: e instanceof Error ? e.message : String(e), 42 + }) 43 + throw e 44 + } 26 45 return await oauthCreateAgent(session) 27 46 } 28 47 ··· 43 62 ): Promise<SessionAccount | undefined> { 44 63 let data: OutputSchema 45 64 try { 46 - const res = await agent.com.atproto.server.getSession() 65 + const res = await Promise.race([ 66 + agent.com.atproto.server.getSession(), 67 + new Promise<never>((_, reject) => 68 + setTimeout( 69 + () => reject(new Error('getSession timed out')), 70 + OAUTH_RESTORE_TIMEOUT_MS, 71 + ), 72 + ), 73 + ]) 47 74 data = res.data 48 75 } catch (e: any) { 49 - logger.error(e) 76 + logger.error('oauthAgentAndSessionToSessionAccount: getSession failed', e) 77 + return undefined 78 + } 79 + let aud: string 80 + try { 81 + const tokenInfo = await Promise.race([ 82 + session.getTokenInfo(false), 83 + new Promise<never>((_, reject) => 84 + setTimeout( 85 + () => reject(new Error('getTokenInfo timed out')), 86 + OAUTH_RESTORE_TIMEOUT_MS, 87 + ), 88 + ), 89 + ]) 90 + aud = tokenInfo.aud 91 + } catch (e: any) { 92 + logger.error('oauthAgentAndSessionToSessionAccount: getTokenInfo failed', e) 50 93 return undefined 51 94 } 52 - const {aud} = await session.getTokenInfo(false) 53 95 return { 54 96 service: session.serverMetadata.issuer, 55 97 did: session.did, ··· 69 111 session?: AtpSessionData 70 112 dispatchUrl?: string 71 113 72 - #oauthSession: OAuthSession 73 - #account?: SessionAccount 74 - 75 114 constructor(session: OAuthSession) { 76 115 super(session) 77 - this.#oauthSession = session 78 116 } 79 117 80 118 async prepare(