gotify/server · warning
no client auth provided
Error message
no client auth provided
What it means
Returned by Logout when there is no authenticated client in the request context. auth.GetClient(ctx) returns nil because no valid session token was presented, so the handler refuses to log out with 403 (after clearing the cookie). Logging out only makes sense with an existing, valid client session.
Source
Thrown at api/session.go:141
// - clientTokenQuery: []
// - basicAuth: []
// responses:
// 200:
// description: Ok
// headers:
// Set-Cookie:
// type: string
// description: cleared session cookie
// 400:
// description: Bad Request
// schema:
// $ref: "#/definitions/Error"
func (a *SessionAPI) Logout(ctx *gin.Context) {
auth.SetCookie(ctx.Writer, "", -1, a.SecureCookie)
client := auth.GetClient(ctx)
if client == nil {
ctx.AbortWithError(403, errors.New("no client auth provided"))
return
}
a.NotifyDeleted(client.UserID, client.Token)
if success := successOrAbort(ctx, 500, a.DB.DeleteClientByID(client.ID)); !success {
return
}
ctx.Status(200)
}
View on GitHub (pinned to 14bfc25627)
Solutions
- Only call logout with a currently valid session token
- Treat 403 on logout as 'already logged out' and clear local state instead of retrying
- Re-login to obtain a fresh token if you need a server-side logout (e.g., to invalidate via NotifyDeleted/DeleteClientByID)
- Check the auth middleware/GetClient wiring if valid tokens still yield nil client
Example fix
// before
await api.logout(); // 403 if token already expired
// after
if (session.token) { await api.logout(); }
localStorage.removeItem('session'); Defensive patterns
Strategy: validation
Validate before calling
function canLogout(session) {
return Boolean(session && session.token);
}
if (!canLogout(currentSession)) {
// nothing to invalidate server-side; just clear local state
clearLocalSession();
} Type guard
function isActiveSession(s) {
return s != null && typeof s.token === 'string' && s.token.length > 0 && (!s.expiresAt || new Date(s.expiresAt) > new Date());
} Try / catch
try {
await api.logout();
} catch (e) {
if (e.status === 403) { /* already logged out */ }
else { throw e; }
} finally {
clearLocalSession();
} Prevention
- Guard logout calls with an unexpired-token check
- Treat 403 from logout as 'nothing to do', not as a failure
- Avoid double-invocation from UI event handlers (disable button after first click)
- If server-side invalidation matters, re-authenticate first when the token is already expired
When it happens
Trigger: DELETE/POST to the logout endpoint without a session token; a token that already expired or was deleted server-side; calling logout twice in a row (the second call finds no client); sending a token for a different auth backend that GetClient does not recognize.
Common situations: Frontend calls logout after the token already expired; stale clients retrying logout after the server restarted and lost session state; API version changes to how tokens are transported; misconfigured auth middleware not populating the client in the gin context.
Related errors
- you are not allowed to access this api
- you are not allowed to create an admin user
- cannot delete internal application
- client not found
- unknown or expired state
AI-assisted analysis of gotify/server@14bfc25627 (2026-09-05).
Data as JSON: /api/errors/75ae4380781baa0c.
Report an issue: GitHub.