Skip to content

Instantly share code, notes, and snippets.

@notrab
Created December 20, 2023 15:24
Show Gist options
  • Select an option

  • Save notrab/40a06d279d0794083f920dbf14584698 to your computer and use it in GitHub Desktop.

Select an option

Save notrab/40a06d279d0794083f920dbf14584698 to your computer and use it in GitHub Desktop.
import NextAuth, { type NextAuthConfig } from "next-auth";
import GitHub from "next-auth/providers/github";
import type {
Adapter,
AdapterAccount,
AdapterSession,
AdapterUser,
VerificationToken as AdapterVerificationToken,
} from "@auth/core/adapters";
import { createClient, type Client as TursoClient } from "@libsql/client";
import { v4 as uuidv4 } from "uuid";
const client = createClient({
url: process.env.LIBSQL_URL!,
authToken: process.env.LIBSQL_AUTH_TOKEN!,
});
function isDate(date: any) {
return (
new Date(date).toString() !== "Invalid Date" && !isNaN(Date.parse(date))
);
}
function TursoAdapter(client: TursoClient): Adapter {
return {
async createUser(user) {
console.log({ user });
const userId = uuidv4();
const result = await client.execute({
sql: "INSERT INTO users (id, name, email, emailVerified, image) VALUES (?, ?, ?, ?, ?)",
args: [
userId,
user.name ?? null,
user.email,
user.emailVerified?.toISOString() ?? null,
user.image ?? null,
],
});
console.log(JSON.stringify({ result }, null, 2));
const { rows } = await client.execute({
sql: "SELECT * FROM users WHERE id = ?",
args: [userId],
});
return rows?.[0];
},
async getUser(id) {
const { rows } = await client.execute({
sql: "SELECT * FROM users WHERE id = ?",
args: [id],
});
return rows?.[0];
},
async getUserByEmail(email) {
const { rows } = await client.execute({
sql: "SELECT * FROM users WHERE email = ?",
args: [email],
});
return rows?.[0];
},
async getUserByAccount(providerAccountId) {
const { rows } = await client.execute({
sql: "SELECT u.* FROM users u JOIN accounts a ON a.userId = u.id WHERE a.providerAccountId = ? AND a.provider = ?",
args: [providerAccountId.providerAccountId, providerAccountId.provider],
});
return rows?.[0];
},
async updateUser(user) {
const { rows } = await client.execute({
sql: "UPDATE users SET name = ?, email = ?, emailVerified = ?, image = ? WHERE id = ?",
args: [
user.name!,
user.email!,
user.emailVerified!,
user.image!,
user.id,
],
});
return rows?.[0];
},
async deleteUser(userId) {
await client.batch([
{
sql: "DELETE FROM accounts WHERE userId = ?",
args: [userId],
},
{
sql: "DELETE FROM sessions WHERE userId = ?",
args: [userId],
},
{
sql: "DELETE FROM users WHERE id = ?",
args: [userId],
},
]);
return null;
},
async linkAccount(account) {
console.log({ account });
try {
const { rows } = await client.execute({
sql: "INSERT INTO accounts (id, userId, type, provider, providerAccountId, refresh_token, access_token, expires_at, token_type, scope, id_token, session_state, oauth_token, oauth_token_secret) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
args: [
uuidv4(),
account.userId,
account.type,
account.provider,
account.providerAccountId,
account.refresh_token ?? null,
account.access_token ?? null,
account.expires_at ?? null,
account.token_type ?? null,
account.scope ?? null,
account.id_token ?? null,
account.session_state ?? null,
account.oauth_token ?? null,
account.oauth_token_secret ?? null,
],
});
return rows?.[0];
} catch (err) {
console.log("oops", err);
return null;
}
},
async unlinkAccount(providerAccountId) {
throw new Error("unlinkAccount Not implemented");
},
async createSession(session) {
const sessionId = uuidv4();
console.log({ expires: session.expires.toISOString() });
await client.execute({
sql: "INSERT INTO sessions (id, sessionToken, userId, expires) VALUES (?,?,?,?)",
args: [
sessionId,
session.sessionToken,
session.userId,
session.expires.toISOString(),
],
});
const { rows } = await client.execute({
sql: "SELECT * FROM sessions WHERE id = ?",
args: [sessionId],
});
const { expires, ...sesh } = rows?.[0];
return {
...sesh,
expires: isDate(expires) ? new Date(expires) : expires,
};
},
async deleteSession(sessionToken) {
await client.execute({
sql: "DELETE FROM sessions WHERE sessionToken = ?",
args: [sessionToken],
});
return null;
},
async getSessionAndUser(sessionToken) {
const sessionResult = await client.execute({
sql: "SELECT id, sessionToken, userId, expires FROM sessions WHERE sessionToken = ?",
args: [sessionToken],
});
const userResult = await client.execute({
sql: "SELECT * FROM users WHERE id = ?",
args: [sessionResult?.rows?.[0]?.userId],
});
return {
session: {
...sessionResult.rows[0],
expires: isDate(sessionResult.rows[0].expires)
? new Date(sessionResult.rows[0].expires)
: sessionResult.rows[0].expires,
},
user: userResult.rows[0],
};
},
async updateSession(session) {
throw new Error("updateSession Not implemented");
},
async createVerificationToken(verificationToken) {
throw new Error("createVerificationToken Not implemented");
},
async useVerificationToken(params) {
throw new Error("useVerificationToken Not implemented");
},
};
}
export const config = {
providers: [GitHub],
adapter: TursoAdapter(client),
callbacks: {},
// debug: true,
} satisfies NextAuthConfig;
export const { handlers, auth, signIn, signOut } = NextAuth(config);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment