@auth/pg-adapter
Version:
Postgres adapter for next-auth.
262 lines (248 loc) • 7.55 kB
text/typescript
/**
* <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", padding: 16}}>
* <p>An official <a href="https://www.postgresql.org/">PostgreSQL</a> adapter for Auth.js / NextAuth.js.</p>
* <a href="https://www.postgresql.org/">
* <img style={{display: "block"}} src="/img/adapters/pg.svg" width="48" />
* </a>
* </div>
*
* ## Installation
*
* ```bash npm2yarn
* npm install next-auth @auth/pg-adapter pg
* ```
*
* @module @auth/pg-adapter
*/
import type {
Adapter,
AdapterUser,
VerificationToken,
AdapterSession,
} from "@auth/core/adapters"
import type { Pool } from "pg"
export function mapExpiresAt(account: any): any {
const expires_at: number = parseInt(account.expires_at)
return {
...account,
expires_at,
}
}
export default function PostgresAdapter(client: Pool): Adapter {
return {
async createVerificationToken(
verificationToken: VerificationToken
): Promise<VerificationToken> {
const { identifier, expires, token } = verificationToken
const sql = `
INSERT INTO verification_token ( identifier, expires, token )
VALUES ($1, $2, $3)
`
await client.query(sql, [identifier, expires, token])
return verificationToken
},
async useVerificationToken({
identifier,
token,
}: {
identifier: string
token: string
}): Promise<VerificationToken> {
const sql = `delete from verification_token
where identifier = $1 and token = $2
RETURNING identifier, expires, token `
const result = await client.query(sql, [identifier, token])
return result.rowCount !== 0 ? result.rows[0] : null
},
async createUser(user: Omit<AdapterUser, "id">) {
const { name, email, emailVerified, image } = user
const sql = `
INSERT INTO users (name, email, "emailVerified", image)
VALUES ($1, $2, $3, $4)
RETURNING id, name, email, "emailVerified", image`
const result = await client.query(sql, [
name,
email,
emailVerified,
image,
])
return result.rows[0]
},
async getUser(id) {
const sql = `select * from users where id = $1`
try {
const result = await client.query(sql, [id])
return result.rowCount === 0 ? null : result.rows[0]
} catch {
return null
}
},
async getUserByEmail(email) {
const sql = `select * from users where email = $1`
const result = await client.query(sql, [email])
return result.rowCount !== 0 ? result.rows[0] : null
},
async getUserByAccount({
providerAccountId,
provider,
}): Promise<AdapterUser | null> {
const sql = `
select u.* from users u join accounts a on u.id = a."userId"
where
a.provider = $1
and
a."providerAccountId" = $2`
const result = await client.query(sql, [provider, providerAccountId])
return result.rowCount !== 0 ? result.rows[0] : null
},
async updateUser(user: Partial<AdapterUser>): Promise<AdapterUser> {
const fetchSql = `select * from users where id = $1`
const query1 = await client.query(fetchSql, [user.id])
const oldUser = query1.rows[0]
const newUser = {
...oldUser,
...user,
}
const { id, name, email, emailVerified, image } = newUser
const updateSql = `
UPDATE users set
name = $2, email = $3, "emailVerified" = $4, image = $5
where id = $1
RETURNING name, id, email, "emailVerified", image
`
const query2 = await client.query(updateSql, [
id,
name,
email,
emailVerified,
image,
])
return query2.rows[0]
},
async linkAccount(account) {
const sql = `
insert into accounts
(
"userId",
provider,
type,
"providerAccountId",
access_token,
expires_at,
refresh_token,
id_token,
scope,
session_state,
token_type
)
values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
returning
id,
"userId",
provider,
type,
"providerAccountId",
access_token,
expires_at,
refresh_token,
id_token,
scope,
session_state,
token_type
`
const params = [
account.userId,
account.provider,
account.type,
account.providerAccountId,
account.access_token,
account.expires_at,
account.refresh_token,
account.id_token,
account.scope,
account.session_state,
account.token_type,
]
const result = await client.query(sql, params)
return mapExpiresAt(result.rows[0])
},
async createSession({ sessionToken, userId, expires }) {
if (userId === undefined) {
throw Error(`userId is undef in createSession`)
}
const sql = `insert into sessions ("userId", expires, "sessionToken")
values ($1, $2, $3)
RETURNING id, "sessionToken", "userId", expires`
const result = await client.query(sql, [userId, expires, sessionToken])
return result.rows[0]
},
async getSessionAndUser(sessionToken: string | undefined): Promise<{
session: AdapterSession
user: AdapterUser
} | null> {
if (sessionToken === undefined) {
return null
}
const result1 = await client.query(
`select * from sessions where "sessionToken" = $1`,
[sessionToken]
)
if (result1.rowCount === 0) {
return null
}
const session: AdapterSession = result1.rows[0]
const result2 = await client.query("select * from users where id = $1", [
session.userId,
])
if (result2.rowCount === 0) {
return null
}
const user = result2.rows[0]
return {
session,
user,
}
},
async updateSession(
session: Partial<AdapterSession> & Pick<AdapterSession, "sessionToken">
): Promise<AdapterSession | null | undefined> {
const { sessionToken } = session
const result1 = await client.query(
`select * from sessions where "sessionToken" = $1`,
[sessionToken]
)
if (result1.rowCount === 0) {
return null
}
const originalSession: AdapterSession = result1.rows[0]
const newSession: AdapterSession = {
...originalSession,
...session,
}
const sql = `
UPDATE sessions set
expires = $2
where "sessionToken" = $1
`
const result = await client.query(sql, [
newSession.sessionToken,
newSession.expires,
])
return result.rows[0]
},
async deleteSession(sessionToken) {
const sql = `delete from sessions where "sessionToken" = $1`
await client.query(sql, [sessionToken])
},
async unlinkAccount(partialAccount) {
const { provider, providerAccountId } = partialAccount
const sql = `delete from accounts where "providerAccountId" = $1 and provider = $2`
await client.query(sql, [providerAccountId, provider])
},
async deleteUser(userId: string) {
await client.query(`delete from users where id = $1`, [userId])
await client.query(`delete from sessions where "userId" = $1`, [userId])
await client.query(`delete from accounts where "userId" = $1`, [userId])
},
}
}