immich-app/immich · error · UnauthorizedException
Authentication required
Error message
Authentication required
What it means
Thrown by validate() when a request carries neither a session/access token nor an API key, so the caller cannot be identified. The service rejects with 401 because no authentication credential exists at all.
Solutions
- Add the x-api-key header (or apikey query param) with a valid API key for machine access
- Log in via web/mobile to obtain a session cookie for user flows
- Ensure the reverse proxy forwards Cookie and x-api-key headers
- Check that your HTTP client actually attaches the configured credentials
Example fix
// before
fetch('/api/albums')
// after
fetch('/api/albums', { headers: { 'x-api-key': process.env.IMMICH_API_KEY } }) Defensive patterns
Strategy: validation
Validate before calling
if (!apiKey && !sessionCookie) throw new Error('Provide x-api-key header or a logged-in session before calling the API'); Type guard
const isAuthed = (r: { headers: Record<string, string> }) => Boolean(r.headers['x-api-key'] || r.headers['cookie']); Try / catch
try { await api.request() } catch (e) { if (e.status === 401 && /Authentication required/.test(e.message)) { /* attach credentials and retry once */ } throw e; } Prevention
- Always attach the API key in machine clients
- Avoid proxies that strip auth headers
- Refresh sessions before long-running jobs
When it happens
Trigger: validate() sees no accessToken in cookies/headers and no apiKey header or query param; both credential paths are undefined.
Common situations: Omitting the x-api-key header in scripts/curl; expired or cleared Immich session cookie; reverse proxy stripping Cookie/x-api-key headers; machine clients with no credentials configured.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of immich-app/immich@f48d4b3321 (2026-09-15).
Data as JSON: /api/errors/a1952075b5123410.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/auth.service.ts:267
const apiKey = (headers[ImmichHeader.ApiKey] || queryParams[ImmichQuery.ApiKey]) as string;
if (shareKey) {
return this.validateSharedLinkKey(shareKey);
}
if (shareSlug) {
return this.validateSharedLinkSlug(shareSlug);
}
if (session) {
return this.validateSession(session, headers);
}
if (apiKey) {
return this.validateApiKey(apiKey);
}
throw new UnauthorizedException('Authentication required');
}
getMobileRedirect(url: string) {
return `${MOBILE_REDIRECT}?${url.split('?', 2)[1] || ''}`;
}
async authorize(dto: OAuthConfigDto) {
const { oauth } = await this.getConfig({ withCache: false });
if (!oauth.enabled) {
throw new BadRequestException('OAuth is not enabled');
}
return await this.oauthRepository.authorize(
oauth,
this.resolveRedirectUri(oauth, dto.redirectUri),
dto.state,
dto.codeChallenge,View on GitHub (pinned to f48d4b3321)