feat(auth): Authentik OIDC sign-in + Gravatar avatars

Adds optional SSO via Authentik (or any OIDC provider) alongside the
existing password flow, and pulls profile images from the provider's
`picture` claim or Gravatar so the sharing UI stops looking anonymous.
Password login stays available as a recovery path; JIT provisioning and
admin-group mapping are env-configurable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-22 21:06:32 +02:00
parent 319be20389
commit e8e1adcf37
20 changed files with 852 additions and 60 deletions

View File

@@ -180,8 +180,8 @@ export function ShareDialog({
{availableUsers.map((u) => (
<SelectItem key={u.id} value={u.username}>
<span className="flex items-center gap-2">
<Avatar name={u.username} size="sm" />
{u.username}
<Avatar name={u.username} imageUrl={u.avatar_url} size="sm" />
{u.display_name || u.username}
</span>
</SelectItem>
))}
@@ -259,11 +259,14 @@ export function ShareDialog({
key={share.id}
className="group flex items-center gap-3 rounded-md px-2 py-1.5 hover:bg-surface-2"
>
<Avatar name={share.shared_with_username} />
<Avatar
name={share.shared_with_username}
imageUrl={share.shared_with_avatar_url}
/>
<div className="min-w-0 flex-1">
<div className="flex items-center gap-1.5">
<span className="truncate text-sm font-medium text-text">
{share.shared_with_username}
{share.shared_with_display_name || share.shared_with_username}
</span>
{share.status === 'pending' && (
<span