@@ -211,6 +211,67 @@ describe("xAI OAuth", () => {
211211 expect ( refreshed . expires ) . toBe ( 121_000 ) ;
212212 } ) ;
213213
214+ it ( "rediscovers the current token endpoint for stale xAI OAuth credentials" , async ( ) => {
215+ const fetchImpl = vi . fn < typeof fetch > ( async ( url , init ) => {
216+ if ( requestUrl ( url ) === XAI_OAUTH_DISCOVERY_URL ) {
217+ expect ( init ?. method ) . toBeUndefined ( ) ;
218+ return jsonResponse ( {
219+ authorization_endpoint : "https://auth.x.ai/oauth2/authorize" ,
220+ token_endpoint : "https://auth.x.ai/oauth2/token" ,
221+ } ) ;
222+ }
223+ expect ( requestUrl ( url ) ) . toBe ( "https://auth.x.ai/oauth2/token" ) ;
224+ expect ( init ?. method ) . toBe ( "POST" ) ;
225+ expect ( requireStringBody ( init ) ) . toContain ( "refresh_token=refresh-1" ) ;
226+ return jsonResponse ( {
227+ access_token : "access-2" ,
228+ refresh_token : "refresh-2" ,
229+ expires_in : 120 ,
230+ } ) ;
231+ } ) ;
232+ const credential = {
233+ type : "oauth" ,
234+ provider : "xai" ,
235+ access : "access-1" ,
236+ refresh : "refresh-1" ,
237+ expires : 100 ,
238+ tokenEndpoint : "https://auth.x.ai/oauth/token" ,
239+ } satisfies OAuthCredential & { tokenEndpoint : string } ;
240+
241+ const refreshed = await refreshXaiOAuthCredential ( credential , { fetchImpl, now : ( ) => 1_000 } ) ;
242+
243+ expect ( fetchImpl ) . toHaveBeenCalledTimes ( 2 ) ;
244+ expect ( fetchImpl . mock . calls . map ( ( [ url ] ) => requestUrl ( url ) ) ) . toEqual ( [
245+ XAI_OAUTH_DISCOVERY_URL ,
246+ "https://auth.x.ai/oauth2/token" ,
247+ ] ) ;
248+ expect ( refreshed ) . toMatchObject ( {
249+ access : "access-2" ,
250+ refresh : "refresh-2" ,
251+ tokenEndpoint : "https://auth.x.ai/oauth2/token" ,
252+ } ) ;
253+ } ) ;
254+
255+ it ( "does not reuse the stale xAI OAuth token endpoint when discovery fails" , async ( ) => {
256+ const fetchImpl = vi . fn < typeof fetch > ( async ( url ) => {
257+ expect ( requestUrl ( url ) ) . toBe ( XAI_OAUTH_DISCOVERY_URL ) ;
258+ throw new Error ( "discovery unavailable" ) ;
259+ } ) ;
260+ const credential = {
261+ type : "oauth" ,
262+ provider : "xai" ,
263+ access : "access-1" ,
264+ refresh : "refresh-1" ,
265+ expires : 100 ,
266+ tokenEndpoint : "https://auth.x.ai/oauth/token" ,
267+ } satisfies OAuthCredential & { tokenEndpoint : string } ;
268+
269+ await expect ( refreshXaiOAuthCredential ( credential , { fetchImpl } ) ) . rejects . toThrow (
270+ "discovery unavailable" ,
271+ ) ;
272+ expect ( fetchImpl ) . toHaveBeenCalledTimes ( 1 ) ;
273+ } ) ;
274+
214275 it ( "does not coerce partial xAI expires_in values" , async ( ) => {
215276 const fetchImpl = vi . fn < typeof fetch > ( async ( ) =>
216277 jsonResponse ( {
0 commit comments