Added gravatar support in case of no avatar

This commit is contained in:
2025-07-19 11:19:40 +02:00
parent 994bdfa41d
commit b838d0f8d6
4 changed files with 68 additions and 1 deletions

19
.env.example Normal file
View File

@@ -0,0 +1,19 @@
# General
NEXT_PUBLIC_BASE_URL=http://localhost:3000
# Database
PG_USER=dev
PG_PASSWORD=dev
PG_HOST=localhost
PG_PORT=5433
PG_DATABASE=dev
# Auth
BETTER_AUTH_SECRET=
BETTER_AUTH_URL=http://localhost:3000
AUTHENTIK_CLIENT_ID=
AUTHENTIK_CLIENT_SECRET=
AUTHENTIK_DISCOVERY_URL=
# other
GRAVATAR_API_KEY=

View File

@@ -4,11 +4,30 @@ import { nextCookies } from "better-auth/next-js"
import { genericOAuth } from "better-auth/plugins" import { genericOAuth } from "better-auth/plugins"
import { db } from "../drizzle/db" import { db } from "../drizzle/db"
import { env } from "../env/server" import { env } from "../env/server"
import { getGravatar } from "../gravatar"
export const auth = betterAuth({ export const auth = betterAuth({
database: drizzleAdapter(db, { database: drizzleAdapter(db, {
provider: "pg" provider: "pg"
}), }),
databaseHooks: {
user: {
create: {
before: async (user) => {
if (user.image) return
const newImage = await getGravatar(user.email)
return {
data: {
...user,
image: newImage
}
}
}
}
}
},
plugins: [ plugins: [
nextCookies(), nextCookies(),
genericOAuth({ genericOAuth({

View File

@@ -12,7 +12,8 @@ export const env = createEnv({
BETTER_AUTH_URL: z.string().min(1), BETTER_AUTH_URL: z.string().min(1),
AUTHENTIK_CLIENT_ID: z.string().min(1), AUTHENTIK_CLIENT_ID: z.string().min(1),
AUTHENTIK_CLIENT_SECRET: z.string().min(1), AUTHENTIK_CLIENT_SECRET: z.string().min(1),
AUTHENTIK_DISCOVERY_URL: z.string().min(1) AUTHENTIK_DISCOVERY_URL: z.string().min(1),
GRAVATAR_API_KEY: z.string().min(1)
}, },
createFinalSchema: (schema) => { createFinalSchema: (schema) => {
return z.object(schema).transform(s => { return z.object(schema).transform(s => {

28
src/lib/gravatar.ts Normal file
View File

@@ -0,0 +1,28 @@
import crypto from "node:crypto"
import { env } from "./env/server"
import { z } from "zod"
const gravatarSchema = z.object({
avatar_url: z.string().url(),
})
export async function getGravatar(email: string) {
const baseUrl = "https://api.gravatar.com/v3/profiles"
const formattedEmail = email.trim().toLowerCase()
const hash = crypto.createHash('sha256').update(formattedEmail).digest('hex')
const res = await fetch(`${baseUrl}/${hash}`, {
headers: {
Authorization: `Bearer ${env.GRAVATAR_API_KEY}`
}
})
if (!res.ok) return null
const json = await res.json()
const { success, data } = gravatarSchema.safeParse(json)
if (!success) return null
return data.avatar_url
}