toeverything/AFFiNE · error · AuthenticationRequired
authentication_required
authentication_required
Error message
You must sign in first to access this resource.
What it means
Thrown by `acceptInviteById` on the link-invitation branch when the mutation is invoked without an authenticated user. Link invites require a session because the resulting membership is bound to the caller's id; the mutation is marked `@Public()` only so that email-invite guests get a clearer error than a generic auth failure. Coded `authentication_required`.
Source
Thrown at packages/backend/server/src/core/workspaces/resolvers/member.ts:711
_workspaceId: string,
@Args('sendAcceptMail', {
nullable: true,
deprecationReason: 'never used',
})
_sendAcceptMail: boolean
) {
const role = await this.models.workspaceUser.getById(inviteId);
// invitation by email
if (role) {
if (user && user.id !== role.userId) {
throw new InvalidInvitation();
}
await this.acceptInvitationByEmail(role);
} else {
// invitation by link
if (!user) {
throw new AuthenticationRequired();
}
const invitation = await this.cache.get<{
workspaceId: string;
inviterUserId: string;
}>(`workspace:inviteLinkId:${inviteId}`);
if (!invitation) {
throw new InvalidInvitation();
}
const role = await this.models.workspaceUser.get(
invitation.workspaceId,
user.id
);
if (role) {
// if status is pending, should accept the invitation directlyView on GitHub (pinned to 26c515e050)
Solutions
- Redirect unauthenticated users to sign-in with a return URL pointing back to the invite.
- Ensure the auth token/cookie is attached to the GraphQL request (credentials: 'include' on the fetcher).
- Refresh the session before retrying if it may have expired.
- For link invites, detect the unauthenticated state up front and send the user through the sign-in flow.
Example fix
// before
await sdk.acceptInviteById({ inviteId }); // link invite, no session
// after
if (!currentUser) {
router.push(`/signin?redirect=${encodeURIComponent('/invite/' + inviteId)}`);
return;
}
await sdk.acceptInviteById({ inviteId }); Defensive patterns
Strategy: validation
Validate before calling
// Require a session for link invites
if (!currentUser) {
router.push(`/signin?redirect=${encodeURIComponent('/invite/' + inviteId)}`);
return;
}
await sdk.acceptInviteById({ inviteId }); Type guard
function hasSession(user) {
return Boolean(user && user.id);
} Try / catch
try {
await sdk.acceptInviteById({ inviteId });
} catch (e) {
if (e.code === 'authentication_required') {
redirectToSignIn(location.pathname);
} else throw e;
} Prevention
- Ensure the auth cookie/token is attached to GraphQL requests (credentials: 'include').
- Redirect unauthenticated users to sign-in with a return URL before accepting.
- Detect session expiry client-side and re-authenticate before retrying.
When it happens
Trigger: Calling `acceptInviteById` with a link invite id (no matching `workspace_user` row) while `user` is `undefined` — e.g. an unauthenticated browser landing on the invite-accept route, or a client that did not attach the session token.
Common situations: Session expired between viewing the invite page and clicking accept; the auth cookie was blocked by third-party cookie restrictions; an unauthenticated user opened the link directly; misconfigured auth gateway stripping headers.
Related errors
- invalid_invitation
- can_not_revoke_yourself
- owner_can_not_leave_workspace
- space_access_denied
- space_not_found
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/12920541ba62e9a9.
Report an issue: GitHub.