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

unlockSession requires an authenticated session (cookie/bearer session), not just any auth context like an API key or shared link. If auth.session is undefined — e.g. the request authenticated via API key or another non-session mechanism — a BadRequestException is thrown.

Solutions

  1. Authenticate with a user login session (cookie or session bearer token) and retry
  2. Do not use x-api-key auth for session unlock endpoints
  3. Ensure the HTTP client forwards session cookies through proxies

Example fix

// before
await api.post('/session/unlock', dto, { headers: { 'x-api-key': key } });
// after
await api.post('/session/unlock', dto, { headers: { cookie: `immich_access_token=${sessionToken}` } });
Defensive patterns

Strategy: validation

Validate before calling

if (!auth.session) throw new Error('unlockSession requires a login session, not API-key auth');

Type guard

const hasSession = (a: AuthDto): a is AuthDto & { session: Session } => !!a.session;

Try / catch

catch (e) { if (e.status === 400 && /session token/.test(e.message)) { /* re-authenticate with session */ } }

Prevention

When it happens

Trigger: Calling the session-unlock endpoint authenticated with an API key or shared-link auth instead of a user session token/cookie.

Common situations: Automation scripts using API keys calling unlockSession; shared-link auth accidentally routed to session endpoints; missing session cookie because cookies were not forwarded by a proxy or client.

Related errors


AI-assisted analysis of immich-app/immich@f48d4b3321 (2026-09-15). Data as JSON: /api/errors/2366b3c4ee4e77b9. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/auth.service.ts:594

          });
        }
      }

      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 f48d4b3321)