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

  1. Obtain the current share key from the owner or regenerate the shared link in the share dialog.
  2. If the link has expired, ask the owner to extend expiresAt or create a new share.
  3. 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=).
  4. 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

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


AI-assisted analysis of immich-app/immich@199723261c (2026-08-12). Data as JSON: /api/errors/c22811fb167fdb94. Report an issue: GitHub.