{"record":{"id":"10fe7e8ce8d29ff7","repo":"fullstackhero/dotnet-starter-kit","slug":"authenticated-user-required-to-toggle-status","errorCode":null,"errorMessage":"authenticated user required to toggle status","messagePattern":"authenticated user required to toggle status","errorType":"exception","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"src/Modules/Identity/Modules.Identity/Services/UserStatusService.cs","lineNumber":55,"sourceCode":"    }\n\n    private void EnsureValidTenant()\n    {\n        if (string.IsNullOrWhiteSpace(multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id))\n        {\n            throw new UnauthorizedException(\"invalid tenant\");\n        }\n    }\n\n    private async Task<ToggleStatusContext> BuildToggleContextAsync(\n        string userId,\n        bool activateUser,\n        CancellationToken cancellationToken)\n    {\n        var actorId = currentUser.GetUserId();\n        if (actorId == Guid.Empty)\n        {\n            throw new UnauthorizedException(\"authenticated user required to toggle status\");\n        }\n\n        var actor = await userManager.FindByIdAsync(actorId.ToString())\n            ?? throw new UnauthorizedException(\"current user not found\");\n\n        var targetUser = await userManager.Users\n            .Where(u => u.Id == userId)\n            .FirstOrDefaultAsync(cancellationToken)\n            ?? throw new NotFoundException(\"User Not Found.\");\n\n        return new ToggleStatusContext(\n            ActorId: actorId,\n            Actor: actor,\n            TargetUser: targetUser,\n            ActivateUser: activateUser,\n            TenantId: multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id);\n    }\n","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Identity/Modules.Identity/Services/UserStatusService.cs#L37-L73","documentation":"Thrown by BuildToggleContextAsync when currentUser.GetUserId() returns Guid.Empty, meaning there is no authenticated user on the current request (or the claims principal lacks the id claim). Activating/deactivating users requires knowing the acting user.","triggerScenarios":"User activate/deactivate endpoints called without a valid JWT, or with a token missing the standard name/sub identifier claim the ICurrentUser service maps.","commonSituations":"Expired or anonymous tokens reaching the endpoint because [Authorize] was bypassed; custom token issuance dropping the uid claim; service-layer calls without an HttpContext user.","solutions":["Re-authenticate so a valid JWT with the user id claim is attached to the request.","Check the token's claims include the identifier claim mapped by ICurrentUser.","Confirm the endpoint is behind [Authorize]/authentication middleware.","For internal calls, run under an authenticated principal rather than none."],"exampleFix":"// before: request sent without auth header\nawait apiFetch(`/api/v1/users/${id}/toggle-status`, { method: \"POST\" });\n// after\nawait apiFetch(`/api/v1/users/${id}/toggle-status`, { method: \"POST\", headers: authHeader() });","handlingStrategy":"type-guard","validationCode":"function hasAuthContext(token) {\n  const claims = decodeJwt(token);\n  return Boolean(claims && (claims.sub || claims.uid));\n}","typeGuard":"function isAuthed(user) {\n  return typeof user?.id === \"string\" && /^[0-9a-fA-F-]{36}$/.test(user.id) && user.id !== \"00000000-0000-0000-0000-000000000000\";\n}","tryCatchPattern":"try { await toggleStatus(userId); } catch (e) {\n  if (e.status === 401 && /authenticated user required/i.test(e.message)) { await relogin(); return retry(); }\n  throw e;\n}","preventionTips":["Ensure all calls carry a fresh Bearer token.","Keep the user-id claim intact when customizing token issuance.","Keep endpoints behind [Authorize]; don't call user-status services anonymously."],"tags":["authentication","identity","claims"],"backgroundTag":"authentication-required","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}