@@ -129,12 +129,10 @@ export async function exchangeAuthorization(
129129 metadata,
130130 authorizationCode,
131131 codeVerifier,
132- redirectUrl,
133132 } : {
134133 metadata : OAuthMetadata ;
135134 authorizationCode : string ;
136135 codeVerifier : string ;
137- redirectUrl : string | URL ;
138136 } ,
139137) : Promise < OAuthTokens > {
140138 const grantType = "authorization_code" ;
@@ -165,7 +163,55 @@ export async function exchangeAuthorization(
165163 grant_type : grantType ,
166164 code : authorizationCode ,
167165 code_verifier : codeVerifier ,
168- redirect_uri : String ( redirectUrl ) ,
166+ } ) ,
167+ } ) ;
168+
169+ if ( ! response . ok ) {
170+ throw new Error ( `Token exchange failed: HTTP ${ response . status } ` ) ;
171+ }
172+
173+ return OAuthTokensSchema . parse ( await response . json ( ) ) ;
174+ }
175+
176+ /**
177+ * Exchange a refresh token for an updated access token.
178+ */
179+ export async function refreshAuthorization (
180+ serverUrl : string | URL ,
181+ {
182+ metadata,
183+ refreshToken,
184+ } : {
185+ metadata : OAuthMetadata ;
186+ refreshToken : string ;
187+ } ,
188+ ) : Promise < OAuthTokens > {
189+ const grantType = "refresh_token" ;
190+
191+ let tokenUrl : URL ;
192+ if ( metadata ) {
193+ tokenUrl = new URL ( metadata . token_endpoint ) ;
194+
195+ if (
196+ metadata . grant_types_supported &&
197+ ! ( grantType in metadata . grant_types_supported )
198+ ) {
199+ throw new Error (
200+ `Incompatible auth server: does not support grant type ${ grantType } ` ,
201+ ) ;
202+ }
203+ } else {
204+ tokenUrl = new URL ( "/token" , serverUrl ) ;
205+ }
206+
207+ const response = await fetch ( tokenUrl , {
208+ method : "POST" ,
209+ headers : {
210+ "Content-Type" : "application/x-www-form-urlencoded" ,
211+ } ,
212+ body : new URLSearchParams ( {
213+ grant_type : grantType ,
214+ refresh_token : refreshToken ,
169215 } ) ,
170216 } ) ;
171217
0 commit comments