HarperFast / HarperFast/harper
GraphQL returns HTTP 500 on auth/authz denials instead of 401/403
- Dominant language
- JavaScript
- Stars
- 89
- Forks
- 10
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 215
Description
## Summary
On the GraphQL surface, authentication/authorization denials surface as **HTTP 500** instead of the correct 401/403 (REST and the operations API return the right codes):
| token | OPS API | REST | GraphQL |
|---|---|---|---|
| valid | 200 | 200 | 200 |
| **expired** | 401 | 401 | **500** |
| tampered payload / signature | 401 | 401 | 401 |
| **under-privileged (valid, no perm)** | 403 | 403 | **500** |
**This is not a security bypass** — expired/tampered tokens are never accepted and no data leaks (verified: the protected value never appears in any response body). It is a wrong-status-code bug on a security-relevant path: a client can't distinguish "re-authenticate / refresh token" from "server error," which breaks auth-retry logic.
## Root cause
`server/graphqlQuerying.ts` (~613-647 / 681-688) maps an `HTTPError` to its status but a plain `Error` to **500**. The resource-layer auth errors (`AccessViolation`, `ClientError` "Must login" / "token expired") carry `statusCode` 401/403 but are **not** `instanceof HTTPError` in that module, so they hit the generic 500 fallthrough and the statusCode is discarded. REST (`auth.ts` / `REST.ts`) honors `error.statusCode`. Reproduced on two independent denial causes, so it's systematic.
(Signature verification itself is correct — `jwt.verify` pins `algorithms:['RS256']`, blocking alg-confusion; tampered tokens are rejected on every surface.)
## Suggested fix
In `graphqlQuerying.ts`, honor `error.statusCode` (or treat `AccessViolation`/`ClientError` like `HTTPError`) so GraphQL returns 401/403 consistent with REST.
## Repro
`integrationTests/qa-scratch/jwt-auth.test.ts` (the one failing assertion is the GraphQL-500 case).
---
_Found via the exploratory QA campaign (qa-explorer), scenario QA-090. Harper `001bf7b9c` (v5.1.0, main)._
Contributor guide
Research direction
Start in server/graphqlQuerying.ts around lines 613-647 and 681-688, then compare status handling in auth.ts and REST.ts. Run integrationTests/qa-scratch/jwt-auth.test.ts and verify that expired-token and under-privileged GraphQL cases return 401 and 403 rather than 500.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- graphql, javascript
- Domain
- api, authentication, authorization
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100