TestHTTP_Token_RefreshGrant: exchange auth_code, then exchange the refresh token for a new pair. Verifies refresh rotation works through the HTTP layer.
(t *testing.T)
| 212 | // refresh token for a new pair. Verifies refresh rotation works through |
| 213 | // the HTTP layer. |
| 214 | func TestHTTP_Token_RefreshGrant(t *testing.T) { |
| 215 | server, provider, _, clientID, userID := setupOAuthAPI(t) |
| 216 | redirectURI := "http://localhost:8765/callback" |
| 217 | verifier, challenge := newPKCE(t) |
| 218 | code := mintAuthCode(t, provider, clientID, userID, redirectURI, challenge) |
| 219 | |
| 220 | // Code exchange. |
| 221 | form := url.Values{} |
| 222 | form.Set("grant_type", "authorization_code") |
| 223 | form.Set("code", code) |
| 224 | form.Set("client_id", clientID) |
| 225 | form.Set("redirect_uri", redirectURI) |
| 226 | form.Set("code_verifier", verifier) |
| 227 | resp, err := http.Post(server.URL+"/oauth2/token", |
| 228 | "application/x-www-form-urlencoded", strings.NewReader(form.Encode())) |
| 229 | if err != nil { |
| 230 | t.Fatal(err) |
| 231 | } |
| 232 | var first struct { |
| 233 | AccessToken string `json:"access_token"` |
| 234 | RefreshToken string `json:"refresh_token"` |
| 235 | } |
| 236 | json.NewDecoder(resp.Body).Decode(&first) |
| 237 | resp.Body.Close() |
| 238 | |
| 239 | // Refresh exchange. |
| 240 | form = url.Values{} |
| 241 | form.Set("grant_type", "refresh_token") |
| 242 | form.Set("refresh_token", first.RefreshToken) |
| 243 | form.Set("client_id", clientID) |
| 244 | resp2, err := http.Post(server.URL+"/oauth2/token", |
| 245 | "application/x-www-form-urlencoded", strings.NewReader(form.Encode())) |
| 246 | if err != nil { |
| 247 | t.Fatal(err) |
| 248 | } |
| 249 | defer resp2.Body.Close() |
| 250 | if resp2.StatusCode != http.StatusOK { |
| 251 | t.Fatalf("refresh exchange status = %d, want 200", resp2.StatusCode) |
| 252 | } |
| 253 | var second struct { |
| 254 | AccessToken string `json:"access_token"` |
| 255 | RefreshToken string `json:"refresh_token"` |
| 256 | } |
| 257 | if err := json.NewDecoder(resp2.Body).Decode(&second); err != nil { |
| 258 | t.Fatal(err) |
| 259 | } |
| 260 | if second.AccessToken == first.AccessToken { |
| 261 | t.Error("refresh should have rotated the access token") |
| 262 | } |
| 263 | if second.RefreshToken == first.RefreshToken { |
| 264 | t.Error("refresh should have rotated the refresh token (single-use)") |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | // TestHTTP_Token_BadPKCE confirms fosite rejects a wrong verifier at |
| 269 | // the HTTP boundary with invalid_grant per RFC 6749 §5.2. |
nothing calls this directly
no test coverage detected