feat(graph): tell password-required from wrong-password on public links

A public link stat that fails for the password came back as a generic 401
"Access token is empty", so a client could not tell "show the password
field" from "the password was wrong". The proxy now marks the two cases
(it holds the auth result) and the graph service renders them as distinct
odata codes, publicLinkPasswordRequired and publicLinkPasswordInvalid, the
way webdav distinguishes ERR_MISSING_BASIC_AUTH from ERR_INVALID_CREDENTIALS.

The distinction rides in the body, never a WWW-Authenticate: Basic header,
which would pop the browser's native auth dialog instead of the app's
password field. The shared header/token contract lives in pkg/middleware.
This commit is contained in:
Dominik Schmidt committed 2026-09-08 11:21:02 +02:00
1 parent 1e6d2ec168
commit b392f43662
5 files changed
+106 -3

No files matched your search

@@ -76,6 +76,10 @@ const (
PreconditionFailed
// ItemIsLocked The item is locked by another process. Try again later.
ItemIsLocked
// PublicLinkPasswordRequired the public link is password protected and no password was provided.
PublicLinkPasswordRequired
// PublicLinkPasswordInvalid a password was provided for the public link but it was rejected.
PublicLinkPasswordInvalid
)
var errorCodes = [...]string{
@@ -99,6 +103,8 @@ var errorCodes = [...]string{
"unauthenticated",
"preconditionFailed",
"itemIsLocked",
"publicLinkPasswordRequired",
"publicLinkPasswordInvalid",
}
// New constructs a new errorcode.Error
@@ -151,6 +157,8 @@ func (e Error) Render(w http.ResponseWriter, r *http.Request) {
status = http.StatusMethodNotAllowed
case ItemIsLocked:
status = http.StatusLocked
case PublicLinkPasswordRequired, PublicLinkPasswordInvalid:
status = http.StatusUnauthorized
case PreconditionFailed:
status = http.StatusPreconditionFailed
default: