Add PrismaORM
preparation for access_token refresh, since JWT cookies cannot be refreshed from the server side
This commit is contained in:
parent
c25bf01d53
commit
b4503db688
9 changed files with 267 additions and 6 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -41,3 +41,6 @@ next-env.d.ts
|
||||||
/result-lib
|
/result-lib
|
||||||
.direnv
|
.direnv
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
# prisma
|
||||||
|
schnabu-web.db
|
||||||
|
|
25
auth.ts
25
auth.ts
|
@ -1,13 +1,18 @@
|
||||||
import NextAuth,{ type DefaultSession } from "next-auth";
|
import NextAuth,{ type DefaultSession } from "next-auth";
|
||||||
import Authentik from "next-auth/providers/authentik";
|
import Authentik from "next-auth/providers/authentik";
|
||||||
|
import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||||
|
import { PrismaClient } from "@prisma/client"
|
||||||
|
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
declare module "next-auth" {
|
declare module "next-auth" {
|
||||||
interface Session {
|
interface Session {
|
||||||
access_token: string;
|
access_token: string | null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { handlers, auth, signIn, signOut } = NextAuth({
|
export const { handlers, auth, signIn, signOut } = NextAuth({
|
||||||
|
adapter: PrismaAdapter(prisma),
|
||||||
providers: [Authentik({
|
providers: [Authentik({
|
||||||
clientId: process.env.AUTH_OIDC_CLIENT_ID,
|
clientId: process.env.AUTH_OIDC_CLIENT_ID,
|
||||||
clientSecret: process.env.AUTH_OIDC_CLIENT_SECRET,
|
clientSecret: process.env.AUTH_OIDC_CLIENT_SECRET,
|
||||||
|
@ -21,12 +26,20 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
|
||||||
}
|
}
|
||||||
return token
|
return token
|
||||||
},
|
},
|
||||||
async session({session, token}) {
|
async session({session, user}) {
|
||||||
if(session) {
|
const getToken = await prisma.account.findFirst({
|
||||||
session = Object.assign({}, session, {access_token: token.access_token})
|
where: {
|
||||||
console.log(session);
|
userId: user.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let accessToken: string | null = null;
|
||||||
|
if (getToken) {
|
||||||
|
accessToken = getToken.access_token!;
|
||||||
}
|
}
|
||||||
return session
|
|
||||||
|
session.access_token = accessToken;
|
||||||
|
return session;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
10
flake.nix
10
flake.nix
|
@ -17,6 +17,9 @@
|
||||||
devShells = eachSystem (pkgs: {
|
devShells = eachSystem (pkgs: {
|
||||||
default = pkgs.mkShell {
|
default = pkgs.mkShell {
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
|
pkgs.openssl
|
||||||
|
pkgs.prisma-engines
|
||||||
|
|
||||||
pkgs.nodejs
|
pkgs.nodejs
|
||||||
|
|
||||||
pkgs.nodePackages.pnpm
|
pkgs.nodePackages.pnpm
|
||||||
|
@ -24,6 +27,13 @@
|
||||||
pkgs.nodePackages.typescript
|
pkgs.nodePackages.typescript
|
||||||
pkgs.nodePackages.typescript-language-server
|
pkgs.nodePackages.typescript-language-server
|
||||||
];
|
];
|
||||||
|
shellHook = ''
|
||||||
|
export PRISMA_SCHEMA_ENGINE_BINARY="${pkgs.prisma-engines}/bin/schema-engine"
|
||||||
|
export PRISMA_QUERY_ENGINE_BINARY="${pkgs.prisma-engines}/bin/query-engine"
|
||||||
|
export PRISMA_QUERY_ENGINE_LIBRARY="${pkgs.prisma-engines}/lib/libquery_engine.node"
|
||||||
|
export PRISMA_FMT_BINARY="${pkgs.prisma-engines}/bin/prisma-fmt"
|
||||||
|
export PATH="$PWD/node_modules/.bin/:$PATH"
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@auth/prisma-adapter": "^2.1.0",
|
||||||
|
"@prisma/client": "^5.14.0",
|
||||||
"next": "14.2.3",
|
"next": "14.2.3",
|
||||||
"next-auth": "5.0.0-beta.18",
|
"next-auth": "5.0.0-beta.18",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
|
@ -21,6 +23,7 @@
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.2.3",
|
"eslint-config-next": "14.2.3",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
|
"prisma": "^5.14.0",
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,12 @@ settings:
|
||||||
excludeLinksFromLockfile: false
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@auth/prisma-adapter':
|
||||||
|
specifier: ^2.1.0
|
||||||
|
version: 2.1.0(@prisma/client@5.14.0)
|
||||||
|
'@prisma/client':
|
||||||
|
specifier: ^5.14.0
|
||||||
|
version: 5.14.0(prisma@5.14.0)
|
||||||
next:
|
next:
|
||||||
specifier: 14.2.3
|
specifier: 14.2.3
|
||||||
version: 14.2.3(react-dom@18.3.1)(react@18.3.1)
|
version: 14.2.3(react-dom@18.3.1)(react@18.3.1)
|
||||||
|
@ -37,6 +43,9 @@ devDependencies:
|
||||||
postcss:
|
postcss:
|
||||||
specifier: ^8
|
specifier: ^8
|
||||||
version: 8.4.38
|
version: 8.4.38
|
||||||
|
prisma:
|
||||||
|
specifier: ^5.14.0
|
||||||
|
version: 5.14.0
|
||||||
tailwindcss:
|
tailwindcss:
|
||||||
specifier: ^3.4.1
|
specifier: ^3.4.1
|
||||||
version: 3.4.3
|
version: 3.4.3
|
||||||
|
@ -74,6 +83,19 @@ packages:
|
||||||
preact-render-to-string: 5.2.3(preact@10.11.3)
|
preact-render-to-string: 5.2.3(preact@10.11.3)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@auth/prisma-adapter@2.1.0(@prisma/client@5.14.0):
|
||||||
|
resolution: {integrity: sha512-x1gYsi8xCFdxpEM6pxhh7OTV+VHB3PgID2L18y8F1kXu+PbcEWt4VZSQ8zk6dI/4YRStcuwQdHe7neCpczr0mg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@prisma/client': '>=2.26.0 || >=3 || >=4 || >=5'
|
||||||
|
dependencies:
|
||||||
|
'@auth/core': 0.31.0
|
||||||
|
'@prisma/client': 5.14.0(prisma@5.14.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@simplewebauthn/browser'
|
||||||
|
- '@simplewebauthn/server'
|
||||||
|
- nodemailer
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@babel/runtime@7.24.5:
|
/@babel/runtime@7.24.5:
|
||||||
resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==}
|
resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
@ -303,6 +325,46 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
/@prisma/client@5.14.0(prisma@5.14.0):
|
||||||
|
resolution: {integrity: sha512-akMSuyvLKeoU4LeyBAUdThP/uhVP3GuLygFE3MlYzaCb3/J8SfsYBE5PkaFuLuVpLyA6sFoW+16z/aPhNAESqg==}
|
||||||
|
engines: {node: '>=16.13'}
|
||||||
|
requiresBuild: true
|
||||||
|
peerDependencies:
|
||||||
|
prisma: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
prisma:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
prisma: 5.14.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@prisma/debug@5.14.0:
|
||||||
|
resolution: {integrity: sha512-iq56qBZuFfX3fCxoxT8gBX33lQzomBU0qIUaEj1RebsKVz1ob/BVH1XSBwwwvRVtZEV1b7Fxx2eVu34Ge/mg3w==}
|
||||||
|
|
||||||
|
/@prisma/engines-version@5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48:
|
||||||
|
resolution: {integrity: sha512-ip6pNkRo1UxWv+6toxNcYvItNYaqQjXdFNGJ+Nuk2eYtRoEdoF13wxo7/jsClJFFenMPVNVqXQDV0oveXnR1cA==}
|
||||||
|
|
||||||
|
/@prisma/engines@5.14.0:
|
||||||
|
resolution: {integrity: sha512-lgxkKZ6IEygVcw6IZZUlPIfLQ9hjSYAtHjZ5r64sCLDgVzsPFCi2XBBJgzPMkOQ5RHzUD4E/dVdpn9+ez8tk1A==}
|
||||||
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
'@prisma/debug': 5.14.0
|
||||||
|
'@prisma/engines-version': 5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48
|
||||||
|
'@prisma/fetch-engine': 5.14.0
|
||||||
|
'@prisma/get-platform': 5.14.0
|
||||||
|
|
||||||
|
/@prisma/fetch-engine@5.14.0:
|
||||||
|
resolution: {integrity: sha512-VrheA9y9DMURK5vu8OJoOgQpxOhas3qF0IBHJ8G/0X44k82kc8E0w98HCn2nhnbOOMwbWsJWXfLC2/F8n5u0gQ==}
|
||||||
|
dependencies:
|
||||||
|
'@prisma/debug': 5.14.0
|
||||||
|
'@prisma/engines-version': 5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48
|
||||||
|
'@prisma/get-platform': 5.14.0
|
||||||
|
|
||||||
|
/@prisma/get-platform@5.14.0:
|
||||||
|
resolution: {integrity: sha512-/yAyBvcEjRv41ynZrhdrPtHgk47xLRRq/o5eWGcUpBJ1YrUZTYB8EoPiopnP7iQrMATK8stXQdPOoVlrzuTQZw==}
|
||||||
|
dependencies:
|
||||||
|
'@prisma/debug': 5.14.0
|
||||||
|
|
||||||
/@rushstack/eslint-patch@1.10.3:
|
/@rushstack/eslint-patch@1.10.3:
|
||||||
resolution: {integrity: sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==}
|
resolution: {integrity: sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -2294,6 +2356,14 @@ packages:
|
||||||
resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==}
|
resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/prisma@5.14.0:
|
||||||
|
resolution: {integrity: sha512-gCNZco7y5XtjrnQYeDJTiVZmT/ncqCr5RY1/Cf8X2wgLRmyh9ayPAGBNziI4qEE4S6SxCH5omQLVo9lmURaJ/Q==}
|
||||||
|
engines: {node: '>=16.13'}
|
||||||
|
hasBin: true
|
||||||
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
'@prisma/engines': 5.14.0
|
||||||
|
|
||||||
/prop-types@15.8.1:
|
/prop-types@15.8.1:
|
||||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
77
prisma/migrations/20240519155316_init_authjs/migration.sql
Normal file
77
prisma/migrations/20240519155316_init_authjs/migration.sql
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "User" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"name" TEXT,
|
||||||
|
"email" TEXT,
|
||||||
|
"emailVerified" DATETIME,
|
||||||
|
"image" TEXT,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Account" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"type" TEXT NOT NULL,
|
||||||
|
"provider" TEXT NOT NULL,
|
||||||
|
"providerAccountId" TEXT NOT NULL,
|
||||||
|
"refresh_token" TEXT,
|
||||||
|
"access_token" TEXT,
|
||||||
|
"expires_at" INTEGER,
|
||||||
|
"token_type" TEXT,
|
||||||
|
"scope" TEXT,
|
||||||
|
"id_token" TEXT,
|
||||||
|
"session_state" TEXT,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL,
|
||||||
|
CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Session" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"sessionToken" TEXT NOT NULL,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"expires" DATETIME NOT NULL,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL,
|
||||||
|
CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "VerificationToken" (
|
||||||
|
"identifier" TEXT NOT NULL,
|
||||||
|
"token" TEXT NOT NULL,
|
||||||
|
"expires" DATETIME NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Authenticator" (
|
||||||
|
"credentialID" TEXT NOT NULL,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"providerAccountId" TEXT NOT NULL,
|
||||||
|
"credentialPublicKey" TEXT NOT NULL,
|
||||||
|
"counter" INTEGER NOT NULL,
|
||||||
|
"credentialDeviceType" TEXT NOT NULL,
|
||||||
|
"credentialBackedUp" BOOLEAN NOT NULL,
|
||||||
|
"transports" TEXT,
|
||||||
|
|
||||||
|
PRIMARY KEY ("userId", "credentialID"),
|
||||||
|
CONSTRAINT "Authenticator_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Authenticator_credentialID_key" ON "Authenticator"("credentialID");
|
3
prisma/migrations/migration_lock.toml
Normal file
3
prisma/migrations/migration_lock.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Please do not edit this file manually
|
||||||
|
# It should be added in your version-control system (i.e. Git)
|
||||||
|
provider = "sqlite"
|
80
prisma/schema-sqlite.prisma
Normal file
80
prisma/schema-sqlite.prisma
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
datasource db {
|
||||||
|
provider = "sqlite"
|
||||||
|
url = "file:./schnabu-web.db"
|
||||||
|
}
|
||||||
|
|
||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
}
|
||||||
|
|
||||||
|
model User {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String?
|
||||||
|
email String? @unique
|
||||||
|
emailVerified DateTime?
|
||||||
|
image String?
|
||||||
|
accounts Account[]
|
||||||
|
sessions Session[]
|
||||||
|
// Optional for WebAuthn support
|
||||||
|
Authenticator Authenticator[]
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
model Account {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
userId String
|
||||||
|
type String
|
||||||
|
provider String
|
||||||
|
providerAccountId String
|
||||||
|
refresh_token String?
|
||||||
|
access_token String?
|
||||||
|
expires_at Int?
|
||||||
|
token_type String?
|
||||||
|
scope String?
|
||||||
|
id_token String?
|
||||||
|
session_state String?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
@@unique([provider, providerAccountId])
|
||||||
|
}
|
||||||
|
|
||||||
|
model Session {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
sessionToken String @unique
|
||||||
|
userId String
|
||||||
|
expires DateTime
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
model VerificationToken {
|
||||||
|
identifier String
|
||||||
|
token String
|
||||||
|
expires DateTime
|
||||||
|
|
||||||
|
@@unique([identifier, token])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional for WebAuthn support
|
||||||
|
model Authenticator {
|
||||||
|
credentialID String @unique
|
||||||
|
userId String
|
||||||
|
providerAccountId String
|
||||||
|
credentialPublicKey String
|
||||||
|
counter Int
|
||||||
|
credentialDeviceType String
|
||||||
|
credentialBackedUp Boolean
|
||||||
|
transports String?
|
||||||
|
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
@@id([userId, credentialID])
|
||||||
|
}
|
|
@ -2,6 +2,8 @@ import { signIn,signOut, auth } from "auth"
|
||||||
|
|
||||||
export default async function Home() {
|
export default async function Home() {
|
||||||
let session = await auth();
|
let session = await auth();
|
||||||
|
|
||||||
|
console.log(session?.access_token)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1>Hello {session?.user?.name}!</h1>
|
<h1>Hello {session?.user?.name}!</h1>
|
||||||
|
|
Loading…
Reference in a new issue