Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions internal/handlers/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,18 @@ func (h *AuthHandler) GitHub(c *fiber.Ctx) error {
return respondError(c, fiber.StatusBadRequest, "invalid_body", "Request body must be valid JSON")
}
if body.Code == "" {
return respondError(c, fiber.StatusBadRequest, "missing_code", "code field is required")
// BUG-API-184 (QA 2026-05-29): the error message used to read
// "code field is required" — accurate but agent-unhelpful. An
// LLM agent that 4xx'd here needed to either know the GitHub
// OAuth code-exchange contract already or open /openapi.json to
// learn what to send. Stamp the full required-fields list inline
// (the request body has only one field today, but the contract
// shape is what the agent needs — `{ "code": "<github_oauth_code>" }`)
// so the message is a self-contained instruction. Keep the
// `missing_code` error code stable for back-compat (agents
// branching on .error stay green).
return respondError(c, fiber.StatusBadRequest, "missing_code",
"Request body is missing the required `code` field. POST `{\"code\": \"<github_oauth_code>\"}` after exchanging your OAuth authorization code at GitHub.")
}

if h.cfg.GitHubClientID == "" || h.cfg.GitHubClientSecret == "" {
Expand Down Expand Up @@ -514,10 +525,18 @@ func (h *AuthHandler) GoogleCallback(c *fiber.Ctx) error {
return respondError(c, fiber.StatusBadRequest, "invalid_body", "Request body must be valid JSON")
}
if body.Code == "" {
return respondError(c, fiber.StatusBadRequest, "missing_code", "code field is required")
// BUG-API-184 (QA 2026-05-29): mirror the GitHub surface so the
// agent-actionable message names BOTH fields the Google callback
// expects (code + redirect_uri). Same code stays for back-compat;
// only the human/agent-facing message gains the shape hint.
return respondError(c, fiber.StatusBadRequest, "missing_code",
"Request body is missing the required `code` field. POST `{\"code\": \"<google_oauth_code>\", \"redirect_uri\": \"<uri>\"}` after exchanging your OAuth authorization code at Google.")
}
if body.RedirectURI == "" {
return respondError(c, fiber.StatusBadRequest, "missing_redirect_uri", "redirect_uri field is required")
// BUG-API-184: same treatment — name the field and the body shape
// so an LLM hitting this 4xx has everything it needs to retry.
return respondError(c, fiber.StatusBadRequest, "missing_redirect_uri",
"Request body is missing the required `redirect_uri` field. POST `{\"code\": \"<google_oauth_code>\", \"redirect_uri\": \"<uri>\"}` matching the redirect_uri you registered with Google.")
}

accessToken, err := exchangeGoogleAuthorizationCode(c.Context(), h.cfg.GoogleClientID, h.cfg.GoogleClientSecret, body.Code, body.RedirectURI)
Expand Down
16 changes: 16 additions & 0 deletions internal/handlers/auth_oauth_coverage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,23 @@ func TestAuth_GitHub_MissingCodeAndBadBody(t *testing.T) {

r2 := oauthPostJSON(t, app, "/auth/github", `{}`)
assert.Equal(t, http.StatusBadRequest, r2.StatusCode)
// BUG-API-184 (QA 2026-05-29): the missing-code message used to read
// "code field is required" — accurate but agent-unhelpful. Pin the
// agent-actionable copy: the message MUST name the field AND the
// expected request body shape so an LLM hitting this 4xx has
// everything it needs to retry without opening the OpenAPI spec.
var env struct {
Error string `json:"error"`
Message string `json:"message"`
}
require.NoError(t, json.NewDecoder(r2.Body).Decode(&env))
r2.Body.Close()
assert.Equal(t, "missing_code", env.Error,
"BUG-API-184: error code MUST stay missing_code for back-compat")
assert.Contains(t, env.Message, "`code`",
"BUG-API-184: message must name the required field (`code`); got %q", env.Message)
assert.Contains(t, env.Message, `{"code":`,
"BUG-API-184: message must show the request body shape `{\"code\": \"<...>\"}`; got %q", env.Message)
}

func TestAuth_GitHub_NotConfigured(t *testing.T) {
Expand Down
Loading