immich-app/immich · warning
Denied access to non-shared route
Error message
Denied access to non-shared route: ${uri} What it means
When a request is authenticated via a shared link, access is restricted to routes explicitly marked sharedLinkRoute. If a shared-link session attempts any other route, this warning is logged with the URI and a ForbiddenException is thrown. It prevents shared-link visitors from using general API surface.
Solutions
- Ensure the shared-link frontend only calls shared-link-permitted endpoints.
- Use a full authenticated user session/API key instead of a shared link for those endpoints.
- Check custom integrations: shared links cannot act as general API credentials.
- If a legitimate shared route is blocked, verify the route metadata is flagged sharedLinkRoute.
Defensive patterns
Strategy: validation
Validate before calling
// use only shared-link-permitted endpoints when authenticated via a shared link
if (authMethod === 'shared-link') {
assert(allowedSharedRoutes.has(endpoint), `${endpoint} is not accessible via shared link`);
} Try / catch
try {
await api.call(endpoint);
} catch (e) {
if (e instanceof ForbiddenException && usingSharedLink) {
showToast('Shared links can only access shared content');
} else throw e;
} Prevention
- Treat shared links as scoped read-only credentials, not API keys.
- Restrict shared-link clients to endpoints explicitly allowed for shared links.
- For broader access, authenticate as a full user instead.
- Review custom integrations for shared-link token leakage into general endpoints.
When it happens
Trigger: A request authenticated with a shared link (authDto.sharedLink set) targets a route whose metadata does not include sharedLinkRoute=true.
Common situations: Shared-link page code or a manual client calling non-shared endpoints (e.g. /api/users, albums API) with shared-link credentials; stale clients probing routes with link tokens.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- Denied access to admin only route
- Attempted to clear cache, but rmtree is not safe on this…
- Elevated permission is required
- Failed login attempt for user
- Forbidden
AI-assisted analysis of immich-app/immich@f48d4b3321 (2026-09-15).
Data as JSON: /api/errors/69bc64fa4c7133cc.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/auth.service.ts:226
password: dto.password,
storageLabel: 'admin',
});
return mapUserAdmin(admin);
}
async authenticate({ headers, queryParams, metadata }: ValidateRequest): Promise<AuthDto> {
const authDto = await this.validate({ headers, queryParams });
const { adminRoute, sharedLinkRoute, uri } = metadata;
const requestedPermission = metadata.permission ?? Permission.All;
if (!authDto.user.isAdmin && adminRoute) {
this.logger.warn(`Denied access to admin only route: ${uri}`);
throw new ForbiddenException('Forbidden');
}
if (authDto.sharedLink && !sharedLinkRoute) {
this.logger.warn(`Denied access to non-shared route: ${uri}`);
throw new ForbiddenException('Forbidden');
}
if (
authDto.apiKey &&
requestedPermission !== false &&
!isGranted({ requested: [requestedPermission], current: authDto.apiKey.permissions })
) {
throw new ForbiddenException(`Missing required permission: ${requestedPermission}`);
}
return authDto;
}
private async validate({ headers, queryParams }: Omit<ValidateRequest, 'metadata'>): Promise<AuthDto> {
const shareKey = (headers[ImmichHeader.SharedLinkKey] || queryParams[ImmichQuery.SharedLinkKey]) as string;
const shareSlug = (headers[ImmichHeader.SharedLinkSlug] || queryParams[ImmichQuery.SharedLinkSlug]) as string;
const session = (headers[ImmichHeader.UserToken] ||View on GitHub (pinned to f48d4b3321)