immich-app/immich · error · UnauthorizedException
Invalid share key
Error message
Invalid share key
What it means
UnauthorizedException (HTTP 401) thrown by validateSharedLinkKey when no valid shared link matches the supplied key bytes. The key is decoded (hex if length 100, else base64url) and looked up via sharedLinkRepository.getByKey; if no row returns or the link is expired/has no user, isValidSharedLink fails.
Source
Thrown at server/src/services/auth.service.ts:500
}
private getCookieOauthState(headers: IncomingHttpHeaders): string | null {
const cookies = parse(headers.cookie || '');
return cookies[ImmichCookie.OAuthState] || null;
}
private getCookieCodeVerifier(headers: IncomingHttpHeaders): string | null {
const cookies = parse(headers.cookie || '');
return cookies[ImmichCookie.OAuthCodeVerifier] || null;
}
async validateSharedLinkKey(key: string | string[]): Promise<AuthDto> {
key = Array.isArray(key) ? key[0] : key;
const bytes = Buffer.from(key, key.length === 100 ? 'hex' : 'base64url');
const sharedLink = await this.sharedLinkRepository.getByKey(bytes);
if (!this.isValidSharedLink(sharedLink)) {
throw new UnauthorizedException('Invalid share key');
}
return { user: sharedLink.user, sharedLink };
}
async validateSharedLinkSlug(slug: string | string[]): Promise<AuthDto> {
slug = Array.isArray(slug) ? slug[0] : slug;
const sharedLink = await this.sharedLinkRepository.getBySlug(slug);
if (!this.isValidSharedLink(sharedLink)) {
throw new UnauthorizedException('Invalid share slug');
}
return { user: sharedLink.user, sharedLink };
}
private isValidSharedLink(
sharedLink?: AuthSharedLink & { user: AuthUser | null },View on GitHub (pinned to 199723261c)
Solutions
- Obtain the current share key from the owner or regenerate the shared link in the share dialog.
- If the link has expired, ask the owner to extend expiresAt or create a new share.
- Verify the key is sent verbatim (watch for URL-decoding by the client) and as the right header (x-immich-share-key) or query (?key=).
- Confirm 100-char hex keys are sent without spaces/newlines.
Example fix
// before
await axios.get('/shared-links/me', { headers: { 'x-immich-share-key': 'typos-and-trailing-' } });
// -> 401 Invalid share key
// after
await axios.get('/shared-links/me', { headers: { 'x-immich-share-key': correctKey.trim() } }); Defensive patterns
Strategy: validation
Validate before calling
function looksLikeValidShareKey(key: string): boolean {
return /^([0-9a-fA-F]{100}|[A-Za-z0-9_-]+)$/.test(key.trim());
} Type guard
function isPlausibleShareKey(value: unknown): value is string {
return typeof value === 'string' && value.trim().length > 0 && looksLikeValidShareKey(value);
} Try / catch
try {
await axios.get('/shared-links/me', { headers: { 'x-immich-share-key': key } });
} catch (e) {
if (e.response?.status === 401) {
showShareExpiredOrRevoked();
} else throw e;
} Prevention
- Trim and validate the key format before sending.
- Treat 401 'Invalid share key' as expired/revoked and prompt for a new share.
- Send the key in the documented header (x-immich-share-key) or query (?key=), not both.
When it happens
Trigger: Any shared-link-capable route called with x-immich-share-key (or ?key=) carrying a wrong, revoked, or expired key. Also when the key format is incorrect (not 100 hex chars or valid base64url) so the decoded bytes do not match any stored hash.
Common situations: User copied an old share key after the owner regenerated it; share link expired (expiresAt passed); link was deleted; trailing characters or URL-encoding issues corrupted the key; client used the share slug as a key.
Related errors
- Authentication required
- User already has a PIN code
- User does not have a PIN code
- Wrong PIN code
- Either password or pinCode is required
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/c22811fb167fdb94.
Report an issue: GitHub.