@@ -129,12 +129,10 @@ export async function exchangeAuthorization(
129
129
metadata,
130
130
authorizationCode,
131
131
codeVerifier,
132
- redirectUrl,
133
132
} : {
134
133
metadata : OAuthMetadata ;
135
134
authorizationCode : string ;
136
135
codeVerifier : string ;
137
- redirectUrl : string | URL ;
138
136
} ,
139
137
) : Promise < OAuthTokens > {
140
138
const grantType = "authorization_code" ;
@@ -165,7 +163,55 @@ export async function exchangeAuthorization(
165
163
grant_type : grantType ,
166
164
code : authorizationCode ,
167
165
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 ,
169
215
} ) ,
170
216
} ) ;
171
217
0 commit comments