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

  1. Only call logout with a currently valid session token
  2. Treat 403 on logout as 'already logged out' and clear local state instead of retrying
  3. Re-login to obtain a fresh token if you need a server-side logout (e.g., to invalidate via NotifyDeleted/DeleteClientByID)
  4. 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

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


AI-assisted analysis of gotify/server@14bfc25627 (2026-09-05). Data as JSON: /api/errors/75ae4380781baa0c. Report an issue: GitHub.