Skip to content

Instantly share code, notes, and snippets.

@gue-ni
Last active April 22, 2024 17:13
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save gue-ni/39751d1122822ee6cf21f756b34c2c5a to your computer and use it in GitHub Desktop.
Save gue-ni/39751d1122822ee6cf21f756b34c2c5a to your computer and use it in GitHub Desktop.
NextAuth.js postgres adapter
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import PostgresAdapter from "../../../lib/adapter";
const pool = new Pool({
user: "postgres",
host: "localhost",
database: "postgres",
password: "postgres",
port: 5432,
});
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
],
adapter: PostgresAdapter(pool),
});
export default function PostgresAdapter(client, options = {}) {
return {
async createUser(user) {
try {
const sql = `
INSERT INTO users (name, email, email_verified, image)
VALUES ($1, $2, $3, $4)
RETURNING id, name, email, email_verified, image`;
let result = await client.query(sql, [user.name, user.email, user.emailVerified, user.image]);
return result.rows[0];
} catch (err) {
console.log(err);
return;
}
},
async getUser(id) {
try {
const sql = `select * from users where id = $1`;
let result = await client.query(sql, [id]);
return result.rows[0];
} catch (err) {
console.log(err);
return;
}
},
async getUserByEmail(email) {
try {
const sql = `select * from users where email = $1`;
let result = await client.query(sql, [email]);
return result.rows[0];
} catch (err) {
console.log(err);
return;
}
},
async getUserByAccount({ providerAccountId, provider }) {
try {
const sql = `
select u.* from users u join accounts a on u.id = a.user_id
where
a.provider_id = $1
and
a.provider_account_id = $2`;
const result = await client.query(sql, [provider, providerAccountId]);
return result.rows[0];
} catch (err) {
console.log(err);
}
},
async updateUser(user) {
try {
} catch (err) {
console.log(err);
return;
}
},
async linkAccount(account) {
try {
const sql = `
insert into accounts
(
user_id,
provider_id,
provider_type,
provider_account_id,
access_token,
access_token_expires
)
values ($1, $2, $3, $4, $5, to_timestamp($6))`;
const params = [
account.userId,
account.provider,
account.type,
account.providerAccountId,
account.access_token,
account.expires_at,
];
await client.query(sql, params);
return account;
} catch (err) {
console.log(err);
return;
}
},
async createSession({ sessionToken, userId, expires }) {
try {
const sql = `insert into sessions (user_id, expires, session_token) values ($1, $2, $3)`;
await client.query(sql, [userId, expires, sessionToken]);
return { sessionToken, userId, expires };
} catch (err) {
console.log(err);
return;
}
},
async getSessionAndUser(sessionToken) {
try {
let result;
result = await client.query("select * from sessions where session_token = $1", [sessionToken]);
let session = result.rows[0];
result = await client.query("select * from users where id = $1", [session.user_id]);
let user = result.rows[0];
return {
session,
user,
};
} catch (err) {
console.log(err);
return;
}
},
async updateSession({ sessionToken }) {
console.log("updateSession", sessionToken);
return;
},
async deleteSession(sessionToken) {
try {
const sql = `delete from sessions where session_token = $1`;
await client.query(sql, [sessionToken]);
} catch (err) {
console.log(err);
return;
}
},
};
}
CREATE TABLE accounts
(
id SERIAL,
compound_id VARCHAR(255), -- removed not null
user_id INTEGER NOT NULL,
provider_type VARCHAR(255) NOT NULL,
provider_id VARCHAR(255) NOT NULL,
provider_account_id VARCHAR(255) NOT NULL,
refresh_token TEXT,
access_token TEXT,
access_token_expires TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE TABLE sessions
(
id SERIAL,
user_id INTEGER NOT NULL,
expires TIMESTAMPTZ NOT NULL,
session_token VARCHAR(255) NOT NULL,
access_token VARCHAR(255), -- removed not null
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE TABLE users
(
id SERIAL,
name VARCHAR(255),
email VARCHAR(255),
email_verified TIMESTAMPTZ,
image TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE UNIQUE INDEX compound_id ON accounts(compound_id);
CREATE INDEX provider_account_id ON accounts(provider_account_id);
CREATE INDEX provider_id ON accounts(provider_id);
CREATE INDEX user_id ON accounts(user_id);
CREATE UNIQUE INDEX session_token ON sessions(session_token);
CREATE UNIQUE INDEX access_token ON sessions(access_token);
CREATE UNIQUE INDEX email ON users(email);
@busaud
Copy link

busaud commented Nov 23, 2022

Awesome!

@codeallday31
Copy link

codeallday31 commented Feb 2, 2023

Thanks for this,
however as I used this on next auth v4, I always getting error about getSessionAndUser method, is this still working?

@bonesoul
Copy link

bonesoul commented Feb 2, 2023

Is this next-auth 4 compatible?

@gue-ni
Copy link
Author

gue-ni commented Feb 5, 2023

Thanks for this, however as I used this on next auth v4, I always getting error about getSessionAndUser method, is this still working?

what error are you getting?

@codeallday31
Copy link

what error are you getting?

on getSessionAndUser, as I check the DB it will not save in the session table.

I'm using Credentials Provider btw

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment