alpha
Login
or
Join now
atpota.to
/
flushes.app
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
This repository has no description
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Overview
Issues
Pulls
Pipelines
fix third paryy pds again
author
damedotblog
date
1 year ago
(Mar 11, 2025, 1:21 PM -0400)
commit
7828a7e7
7828a7e75dddf949b333fe47b2fd398509e5945e
parent
41745ad4
41745ad4e3d2c453a69b7b950384865ed4b4be89
+127
-40
2 changed files
Expand all
Collapse all
Unified
Split
app
src
lib
auth-context.tsx
bluesky-api.ts
+19
-1
app/src/lib/auth-context.tsx
Reviewed
···
88
88
89
89
// Refresh the token with enhanced error handling
90
90
try {
91
91
+
// CRITICAL FIX: Follow the same server selection logic as in refreshAccessToken
92
92
+
let refreshAuthServer = pdsEndpoint;
93
93
+
94
94
+
// For bsky.network PDSes, use bsky.social
95
95
+
if (pdsEndpoint.includes('bsky.network')) {
96
96
+
console.log('[AUTH CONTEXT] Using bsky.social for token refresh with bsky.network PDS');
97
97
+
refreshAuthServer = 'https://bsky.social';
98
98
+
} else if (pdsEndpoint.includes('bsky.social')) {
99
99
+
// Already using bsky.social
100
100
+
console.log('[AUTH CONTEXT] Using bsky.social directly for token refresh');
101
101
+
} else {
102
102
+
// For third-party PDSes, use their own endpoint
103
103
+
console.log('[AUTH CONTEXT] Using third-party PDS\'s own endpoint for token refresh:', pdsEndpoint);
104
104
+
}
105
105
+
91
106
const { accessToken: newAccessToken, refreshToken: newRefreshToken, dpopNonce: newNonce } =
92
92
-
await refreshAccessToken(refreshToken, keyPair, pdsEndpoint);
107
107
+
await refreshAccessToken(refreshToken, keyPair, refreshAuthServer);
93
108
94
109
// Update state
95
110
setAccessToken(newAccessToken);
···
101
116
localStorage.setItem('accessToken', newAccessToken);
102
117
localStorage.setItem('refreshToken', newRefreshToken);
103
118
if (newNonce) localStorage.setItem('dpopNonce', newNonce);
119
119
+
// Ensure we have the PDS endpoint stored consistently
120
120
+
localStorage.setItem('pdsEndpoint', pdsEndpoint);
121
121
+
localStorage.setItem('bsky_auth_pdsEndpoint', pdsEndpoint);
104
122
}
105
123
106
124
setLastTokenRefresh(Date.now());
+108
-39
app/src/lib/bluesky-api.ts
Reviewed
···
92
92
// Endpoint for token refresh
93
93
const tokenEndpoint = `${authServer}/oauth/token`;
94
94
95
95
-
// First, ALWAYS get a fresh nonce before attempting token refresh
95
95
+
// For third-party PDS, directly get nonce from PDS endpoint
96
96
+
// This is critical because third-party PDSes need their own specific nonce
96
97
let dpopNonce = null;
97
97
-
try {
98
98
-
// Try server-side nonce retrieval first
99
99
-
console.log('[TOKEN REFRESH] Getting fresh nonce from server API');
100
100
-
const nonceResponse = await fetch('/api/auth/nonce', {
101
101
-
method: 'POST',
102
102
-
headers: { 'Content-Type': 'application/json' },
103
103
-
body: JSON.stringify({ pdsEndpoint })
104
104
-
});
105
105
-
106
106
-
if (nonceResponse.ok) {
107
107
-
const nonceData = await nonceResponse.json();
108
108
-
if (nonceData.nonce) {
109
109
-
dpopNonce = nonceData.nonce;
110
110
-
console.log('[TOKEN REFRESH] Got fresh nonce from server API:', dpopNonce);
98
98
+
99
99
+
// Special handling for third-party PDS token refresh
100
100
+
if (!authServer.includes('bsky.social') && !authServer.includes('bsky.network')) {
101
101
+
try {
102
102
+
// For third-party PDS, use a two-step approach to get the valid nonce:
103
103
+
console.log('[TOKEN REFRESH] Direct nonce retrieval from third-party PDS');
104
104
+
105
105
+
// Step 1: Send an empty token refresh request to get a nonce error
106
106
+
// This ensures we get the exact format of nonce the PDS expects
107
107
+
console.log('[TOKEN REFRESH] Step 1: Sending probe request to get nonce');
108
108
+
const probeResponse = await fetch(tokenEndpoint, {
109
109
+
method: 'POST',
110
110
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
111
111
+
body: new URLSearchParams({
112
112
+
'grant_type': 'refresh_token',
113
113
+
'refresh_token': refreshToken,
114
114
+
'client_id': 'https://flushes.app/client-metadata.json'
115
115
+
})
116
116
+
});
117
117
+
118
118
+
// Get the nonce from the error response
119
119
+
const probeNonce = probeResponse.headers.get('DPoP-Nonce');
120
120
+
if (probeNonce) {
121
121
+
console.log('[TOKEN REFRESH] Got DPoP-Nonce from probe response:', probeNonce);
122
122
+
dpopNonce = probeNonce;
123
123
+
} else {
124
124
+
// Try to parse the response body for a nonce in the error message
125
125
+
try {
126
126
+
const probeData = await probeResponse.json();
127
127
+
if (probeData.error === 'use_dpop_nonce' && probeData.nonce) {
128
128
+
console.log('[TOKEN REFRESH] Got nonce from error body:', probeData.nonce);
129
129
+
dpopNonce = probeData.nonce;
130
130
+
}
131
131
+
} catch (e) {
132
132
+
console.warn('[TOKEN REFRESH] Failed to parse probe response:', e);
133
133
+
}
111
134
}
135
135
+
} catch (directError) {
136
136
+
console.warn('[TOKEN REFRESH] Direct nonce retrieval failed:', directError);
112
137
}
113
113
-
114
114
-
// If server-side retrieval fails, try client-side
115
115
-
if (!dpopNonce) {
116
116
-
console.log('[TOKEN REFRESH] Trying HEAD request for nonce');
117
117
-
const headResponse = await fetch(tokenEndpoint, { method: 'HEAD' });
118
118
-
dpopNonce = headResponse.headers.get('DPoP-Nonce');
119
119
-
}
120
120
-
121
121
-
// If still no nonce, try POST probe
122
122
-
if (!dpopNonce) {
123
123
-
console.log('[TOKEN REFRESH] Trying POST probe for nonce');
124
124
-
const probeResponse = await fetch(tokenEndpoint, {
138
138
+
}
139
139
+
140
140
+
// Fall back to standard nonce retrieval methods if direct method failed
141
141
+
if (!dpopNonce) {
142
142
+
try {
143
143
+
// Try server-side nonce retrieval first
144
144
+
console.log('[TOKEN REFRESH] Getting fresh nonce from server API');
145
145
+
const nonceResponse = await fetch('/api/auth/nonce', {
125
146
method: 'POST',
126
126
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
127
127
-
body: new URLSearchParams({}) // Empty body to trigger error response with nonce
147
147
+
headers: { 'Content-Type': 'application/json' },
148
148
+
body: JSON.stringify({ pdsEndpoint: authServer }) // Use the correct server
128
149
});
129
129
-
dpopNonce = probeResponse.headers.get('DPoP-Nonce');
150
150
+
151
151
+
if (nonceResponse.ok) {
152
152
+
const nonceData = await nonceResponse.json();
153
153
+
if (nonceData.nonce) {
154
154
+
dpopNonce = nonceData.nonce;
155
155
+
console.log('[TOKEN REFRESH] Got fresh nonce from server API:', dpopNonce);
156
156
+
}
157
157
+
}
158
158
+
159
159
+
// If server-side retrieval fails, try client-side
160
160
+
if (!dpopNonce) {
161
161
+
console.log('[TOKEN REFRESH] Trying HEAD request for nonce');
162
162
+
const headResponse = await fetch(tokenEndpoint, { method: 'HEAD' });
163
163
+
dpopNonce = headResponse.headers.get('DPoP-Nonce');
164
164
+
}
165
165
+
166
166
+
// If still no nonce, try POST probe
167
167
+
if (!dpopNonce) {
168
168
+
console.log('[TOKEN REFRESH] Trying POST probe for nonce');
169
169
+
const probeResponse = await fetch(tokenEndpoint, {
170
170
+
method: 'POST',
171
171
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
172
172
+
body: new URLSearchParams({}) // Empty body to trigger error response with nonce
173
173
+
});
174
174
+
dpopNonce = probeResponse.headers.get('DPoP-Nonce');
175
175
+
}
176
176
+
} catch (nonceError) {
177
177
+
console.warn('[TOKEN REFRESH] Failed to get initial nonce:', nonceError);
130
178
}
131
131
-
} catch (nonceError) {
132
132
-
console.warn('[TOKEN REFRESH] Failed to get initial nonce:', nonceError);
133
179
}
134
180
135
181
if (!dpopNonce) {
···
165
211
});
166
212
167
213
// Handle nonce error explicitly - this is the critical part!
168
168
-
if (response.status === 401) {
214
214
+
if (response.status === 401 || response.status === 400) {
169
215
let responseBody;
170
216
try {
171
217
responseBody = await response.json();
···
173
219
responseBody = {};
174
220
}
175
221
176
176
-
const newNonce = response.headers.get('DPoP-Nonce');
222
222
+
// Try to get nonce from multiple sources
223
223
+
let newNonce = response.headers.get('DPoP-Nonce');
224
224
+
225
225
+
// Also check for nonce in the response body (some PDSes return it there)
226
226
+
if (!newNonce && responseBody.nonce) {
227
227
+
newNonce = responseBody.nonce;
228
228
+
console.log('[TOKEN REFRESH] Found nonce in response body:', newNonce);
229
229
+
}
230
230
+
231
231
+
// Some servers use DPoP-Nonce header instead of nonce in body
232
232
+
if (!newNonce && response.headers.get('DPoP-Nonce')) {
233
233
+
newNonce = response.headers.get('DPoP-Nonce');
234
234
+
console.log('[TOKEN REFRESH] Found DPoP-Nonce in response headers:', newNonce);
235
235
+
}
177
236
178
237
// Check for DPoP nonce error
179
179
-
if (
180
180
-
(responseBody.error === 'use_dpop_nonce' ||
181
181
-
(responseBody.error_description && responseBody.error_description.includes('nonce'))) &&
182
182
-
newNonce
183
183
-
) {
238
238
+
const isNonceError =
239
239
+
responseBody.error === 'use_dpop_nonce' ||
240
240
+
responseBody.error === 'invalid_dpop_proof' ||
241
241
+
(responseBody.error_description && (
242
242
+
responseBody.error_description.includes('nonce') ||
243
243
+
responseBody.error_description.includes('DPoP')
244
244
+
));
245
245
+
246
246
+
if (isNonceError && newNonce) {
184
247
console.log('[TOKEN REFRESH] Received nonce error, retrying with new nonce:', newNonce);
185
248
186
249
// Generate new DPoP token with the provided nonce
···
414
477
// For third-party PDSes, use their own endpoint
415
478
console.log('[AUTH CHECK] Will use third-party PDS\'s own endpoint:', pdsEndpoint);
416
479
// Keep refreshAuthServer as the original PDS endpoint
480
480
+
481
481
+
// Ensure we update the PDS endpoint everywhere
482
482
+
if (typeof localStorage !== 'undefined') {
483
483
+
localStorage.setItem('pdsEndpoint', pdsEndpoint);
484
484
+
localStorage.setItem('bsky_auth_pdsEndpoint', pdsEndpoint);
485
485
+
}
417
486
}
418
487
419
488
const { accessToken: newAccessToken, refreshToken: newRefreshToken, dpopNonce: newNonce } =