immich-app/immich · warning · UnauthorizedException
Password required
Error message
Password required
What it means
In SharedLinkService.getMine(), when the resolved shared link HAS a password, the caller must present a valid auth token computed from {id, password}. If none of the request's authTokens match asToken({id, password}), UnauthorizedException 'Password required' is thrown (shared-link.service.ts:58, HTTP 401).
Source
Thrown at server/src/services/shared-link.service.ts:58
throw new UnauthorizedException('Invalid password');
}
return {
sharedLink: mapSharedLink(sharedLink, { stripAssetMetadata: !sharedLink.showExif }),
token: this.asToken({ id, password }),
};
}
async getMine(auth: AuthDto, authTokens: string[]) {
if (!auth.sharedLink) {
throw new ForbiddenException();
}
const sharedLink = await this.findOrFail(auth.user.id, auth.sharedLink.id);
const { id, password } = sharedLink;
if (password && !authTokens.includes(this.asToken({ id, password }))) {
throw new UnauthorizedException('Password required');
}
return mapSharedLink(sharedLink, { stripAssetMetadata: !sharedLink.showExif });
}
async get(auth: AuthDto, id: string): Promise<SharedLinkResponseDto> {
const sharedLink = await this.findOrFail(auth.user.id, id);
return mapSharedLink(sharedLink, { stripAssetMetadata: false });
}
async create(auth: AuthDto, dto: SharedLinkCreateDto): Promise<SharedLinkResponseDto> {
switch (dto.type) {
case SharedLinkType.Album: {
if (!dto.albumId) {
throw new BadRequestException('Invalid albumId');
}
await this.requireAccess({ auth, permission: Permission.AlbumShare, ids: [dto.albumId] });
break;View on GitHub (pinned to 199723261c)
Solutions
- Complete the shared-link login() flow first; the returned token is what authorizes getMine.
- Ensure the shared-link auth token/cookie is sent with the getMine request.
- If the owner changed the password, re-run login to obtain a fresh token.
Example fix
// before - skip login
fetch('/shared-links/me', { headers: { 'x-immich-share-key': key } });
// after - login first, then read
const { token } = await sharedLinkApi.login({ password });
fetch('/shared-links/me', { headers: { 'x-immich-share-key': key, 'x-immich-share-token': token } }); Defensive patterns
Strategy: validation
Validate before calling
// Ensure a shared-link auth token exists before calling getMine.
let token = getShareAuthToken();
if (!token) {
const res = await sharedLinkApi.login({ password });
token = res.token;
storeShareAuthToken(token);
}
await sharedLinkApi.getMine({ shareKey, token }); Type guard
const hasShareAuthToken = (tokens: string[] | undefined): boolean => Array.isArray(tokens) && tokens.length > 0;
Try / catch
try {
await sharedLinkApi.getMine();
} catch (e) {
if (e instanceof UnauthorizedException && /password required/i.test(e.message)) {
// run login flow, then retry getMine
const { token } = await sharedLinkApi.login({ password });
return retryGetMineWith(token);
} else throw e;
} Prevention
- Complete login() and persist the returned token before any getMine call.
- Re-run login when the owner changes the password (token becomes invalid).
When it happens
Trigger: Accessing the shared-link viewer (getMine) for a password-protected link without first completing the login flow that mints the shared-link auth cookie/token. The token is only issued by a successful login().
Common situations: Loading the share URL directly without the password cookie set, the auth cookie expiring or being cleared, or the password having changed since the token was issued.
Related errors
- Invalid password
- Error backchannel logout: token validation failed
- Invalid logout token: no claims found
- Invalid logout token: it must contain either a sub or a sid
- Wrong password
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/cd4a8c2a38e3b999.
Report an issue: GitHub.