immich-app/immich · error · BadRequestException
This endpoint can only be used with a session token
Error message
This endpoint can only be used with a session token
What it means
Thrown by AuthService.unlockSession when the incoming AuthDto has no session object. unlockSession needs a real session to update pinExpiresAt, so authenticating with anything other than a session token (an API key or a share link) is a client-side usage error, not an auth failure.
Source
Thrown at server/src/services/auth.service.ts:590
});
}
}
return {
user: session.user,
session: {
id: session.id,
hasElevatedPermission,
},
};
}
throw new UnauthorizedException('Invalid user token');
}
async unlockSession(auth: AuthDto, dto: SessionUnlockDto): Promise<void> {
if (!auth.session) {
throw new BadRequestException('This endpoint can only be used with a session token');
}
const user = await this.userRepository.getForPinCode(auth.user.id);
this.validatePinCode(user, { pinCode: dto.pinCode });
await this.sessionRepository.update(auth.session.id, {
pinExpiresAt: DateTime.now().plus({ minutes: 15 }).toJSDate(),
});
}
async lockSession(auth: AuthDto): Promise<void> {
if (!auth.session) {
throw new BadRequestException('This endpoint can only be used with a session token');
}
await this.sessionRepository.update(auth.session.id, { pinExpiresAt: null });
}
View on GitHub (pinned to 199723261c)
Solutions
- Ensure the client uses a session token (from login) for unlock, not an API key or share link.
- Guard the UI so the unlock flow is only reachable when a locked session is actually present.
- Inspect the request: confirm an Authorization: Bearer <session-token> or session cookie is attached.
Example fix
// before
if (auth.user) {
await authService.unlockSession(auth, { pinCode });
}
// after
if (!auth.session) {
throw new BadRequestException('Unlock requires a session token; re-authenticate via login.');
}
await authService.unlockSession(auth, { pinCode }); Defensive patterns
Strategy: validation
Validate before calling
if (!auth.session) {
throw new BadRequestException('Unlock requires a session token; log in first.');
} Type guard
function hasSession(auth: AuthDto): auth is AuthDto & { session: { id: string } } {
return !!auth.session && typeof auth.session.id === 'string';
} Prevention
- Only show the PIN-unlock UI when a session token (not an API key) is active.
- Authenticate unlock requests with a session cookie/bearer, never an x-api-key.
- Track auth kind client-side so endpoint compatibility is known before the call.
When it happens
Trigger: Calling the session-unlock endpoint while authenticated via an API key or a shared link (auth.session is undefined), or calling it with no authentication at all.
Common situations: A mobile/desktop client persisted the wrong token type and calls /auth/unlock with an API key; an automation script reuses an API key against an endpoint that only accepts session tokens; a deep link opened the unlock screen with no active session.
Related errors
- Unauthorized
- Invalid logout token: it must contain either a sub or a sid
- User already has a PIN code
- User does not have a PIN code
- Wrong PIN code
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/2366b3c4ee4e77b9.
Report an issue: GitHub.