this repo has no description
0
fork

Configure Feed

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

oauth client: update RefreshTokens to use postToAuthServer helper

+4 -56
+4 -56
atproto/auth/oauth/session.go
··· 81 81 } 82 82 83 83 // Helper method to handle DPoP retries and client assertions (if the client is confidential) 84 - // body object will be url-encoded (can be InitialTokenRequest, RefreshTokenRequest, RevocationRequest) 84 + // body object will be url-encoded (expected to be either RefreshTokenRequest or RevocationRequest) 85 85 // expects sess.lk to be held by caller 86 - // on success, caller is responsible for closing the response body 86 + // if a non-nil *http.Response is returned, the caller is responsible for closing the response body 87 87 func (sess *ClientSession) postToAuthServer(ctx context.Context, url string, body interface{}) (*http.Response, error) { 88 88 vals, err := query.Values(body) 89 89 if err != nil { ··· 155 155 GrantType: "refresh_token", 156 156 RefreshToken: sess.Data.RefreshToken, 157 157 } 158 - tokenURL := sess.Data.AuthServerTokenEndpoint 159 158 160 - if sess.Config.IsConfidential() { 161 - clientAssertion, err := sess.Config.NewClientAssertion(sess.Data.AuthServerURL) 162 - if err != nil { 163 - return "", err 164 - } 165 - body.ClientAssertionType = &ClientAssertionJWTBearer 166 - body.ClientAssertion = &clientAssertion 167 - } 168 - 169 - vals, err := query.Values(body) 159 + resp, err := sess.postToAuthServer(ctx, sess.Data.AuthServerTokenEndpoint, body) 170 160 if err != nil { 171 - return "", err 172 - } 173 - bodyBytes := []byte(vals.Encode()) 174 - 175 - var resp *http.Response 176 - for range 2 { 177 - dpopJWT, err := NewAuthDPoP("POST", sess.Data.AuthServerTokenEndpoint, sess.Data.DPoPAuthServerNonce, sess.DPoPPrivateKey) 178 - if err != nil { 179 - return "", err 180 - } 181 - 182 - req, err := http.NewRequestWithContext(ctx, "POST", tokenURL, bytes.NewBuffer(bodyBytes)) 183 - if err != nil { 184 - return "", err 185 - } 186 - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 187 - req.Header.Set("DPoP", dpopJWT) 188 - 189 - resp, err = sess.Client.Do(req) 190 - if err != nil { 191 - return "", err 192 - } 193 - 194 - // always check if a new DPoP nonce was provided, and proactively update session data (even if there was not an explicit error) 195 - dpopNonceHdr := resp.Header.Get("DPoP-Nonce") 196 - if dpopNonceHdr != "" && dpopNonceHdr != sess.Data.DPoPAuthServerNonce { 197 - sess.Data.DPoPAuthServerNonce = dpopNonceHdr 198 - } 199 - 200 - // check for an error condition caused by an out of date DPoP nonce 201 - // note that the HTTP status code is 400 Bad Request on the Auth Server token endpoint, not 401 Unauthorized like it would be on Resource Server requests 202 - if resp.StatusCode == http.StatusBadRequest && dpopNonceHdr != "" { 203 - // parseAuthErrorReason() always closes resp.Body 204 - reason := parseAuthErrorReason(resp, "token-refresh") 205 - if reason == "use_dpop_nonce" { 206 - // already updated nonce value above; loop around and try again 207 - continue 208 - } 209 - return "", fmt.Errorf("token refresh failed (HTTP %d): %s", resp.StatusCode, reason) 210 - } 211 - 212 - // otherwise process response (success or other error type) 213 - break 161 + return "", fmt.Errorf("token refresh failed: %w", err) 214 162 } 215 163 216 164 defer resp.Body.Close()