mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
15 Commits
feat/hasur
...
next-auth@
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac5d8a9795 | ||
|
|
965c6267e2 | ||
|
|
bfc429d20b | ||
|
|
2d8e910a19 | ||
|
|
d16e04848e | ||
|
|
ff3a52895b | ||
|
|
e6e03e8842 | ||
|
|
715aad9474 | ||
|
|
902bf92a85 | ||
|
|
44f2a47e6e | ||
|
|
a3b92dbaec | ||
|
|
bdd3ab2816 | ||
|
|
ba55f06585 | ||
|
|
d2b877fb28 | ||
|
|
658b22d9fb |
@@ -1161,9 +1161,9 @@ isexe@^2.0.0:
|
||||
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
|
||||
|
||||
jose@^4.1.4, jose@^4.3.7:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/jose/-/jose-4.5.0.tgz#92829d8cf846351eb55aaaf94f252fb1d191f2d5"
|
||||
integrity sha512-GFcVFQwYQKbQTUOo2JlpFGXTkgBw26uzDsRMD2q1WgSKNSnpKS9Ug7bdQ8dS+p4sZHNH6iRPu6WK2jLIjspaMA==
|
||||
version "4.9.3"
|
||||
resolved "https://registry.yarnpkg.com/jose/-/jose-4.9.3.tgz#890abd3f26725fe0f2aa720bc2f7835702b624db"
|
||||
integrity sha512-f8E/z+T3Q0kA9txzH2DKvH/ds2uggcw0m3vVPSB9HrSkrQ7mojjifvS7aR8cw+lQl2Fcmx9npwaHpM/M3GD8UQ==
|
||||
|
||||
js-yaml@^4.1.0:
|
||||
version "4.1.0"
|
||||
|
||||
@@ -114,6 +114,12 @@ session: {
|
||||
// Use it to limit write operations. Set to 0 to always update the database.
|
||||
// Note: This option is ignored if using JSON Web Tokens
|
||||
updateAge: 24 * 60 * 60, // 24 hours
|
||||
|
||||
// The session token is usually either a random UUID or string, however if you
|
||||
// need a more customized session token string, you can define your own generate function.
|
||||
generateSessionToken: () => {
|
||||
return randomUUID?.() ?? randomBytes(32).toString("hex")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ export default function Component() {
|
||||
|
||||
Due to the way how Next.js handles `getServerSideProps` and `getInitialProps`, every protected page load has to make a server-side request to check if the session is valid and then generate the requested page (SSR). This increases server load, and if you are good with making the requests from the client, there is an alternative. You can use `useSession` in a way that makes sure you always have a valid session. If after the initial loading state there was no session found, you can define the appropriate action to respond.
|
||||
|
||||
The default behavior is to redirect the user to the sign-in page, from where - after a successful login - they will be sent back to the page they started on. You can also define an `onFail()` callback, if you would like to do something else:
|
||||
The default behavior is to redirect the user to the sign-in page, from where - after a successful login - they will be sent back to the page they started on. You can also define an `onUnauthenticated()` callback, if you would like to do something else:
|
||||
|
||||
#### Example
|
||||
|
||||
|
||||
@@ -24,7 +24,11 @@ providers: [
|
||||
AtlassianProvider({
|
||||
clientId: process.env.ATLASSIAN_CLIENT_ID,
|
||||
clientSecret: process.env.ATLASSIAN_CLIENT_SECRET,
|
||||
scope: "write:jira-work read:jira-work read:jira-user offline_access read:me"
|
||||
authorization: {
|
||||
params: {
|
||||
scope: "write:jira-work read:jira-work read:jira-user offline_access read:me"
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
...
|
||||
|
||||
@@ -42,13 +42,19 @@ export default function Page() {
|
||||
|
||||
### Next.js (Middleware)
|
||||
|
||||
With NextAuth.js 4.2.0 and Next.js 12, you can now protect your pages via the middleware pattern more easily. If you would like to protect all pages, you can create a `_middleware.js` file in your root `pages` directory which looks like this.
|
||||
With NextAuth.js 4.2.0 and Next.js 12, you can now protect your pages via the middleware pattern more easily. If you would like to protect all pages, you can create a `_middleware.js` file in your root `pages` directory which looks like this:
|
||||
|
||||
```js title="/middleware.js"
|
||||
export { default } from "next-auth/middleware"
|
||||
```
|
||||
|
||||
Otherwise, if you only want to protect a subset of pages, you could put it in a subdirectory as well, for example in `/pages/admin/_middleware.js` would protect all pages under `/admin`.
|
||||
If you only want to secure certain pages, export a `config` object with a `matcher`:
|
||||
|
||||
```js
|
||||
export { default } from "next-auth/middleware"
|
||||
|
||||
export const config = { matcher: ["/dashboard"] }
|
||||
```
|
||||
|
||||
For the time being, the `withAuth` middleware only supports `"jwt"` as [session strategy](https://next-auth.js.org/configuration/options#session).
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"build:app": "turbo run build --filter=next-auth-app --include-dependencies",
|
||||
"build": "turbo run build --filter=next-auth --filter=@next-auth/* --no-deps",
|
||||
"lint": "turbo run lint --filter=!next-auth-docs --parallel",
|
||||
"test": "turbo run test --concurrency=1 --filter=!@next-auth/pouchdb-adapter --filter=!@next-auth/mikro-orm-adapter --filter=!@next-auth/upstash-redis-adapter --filter=!next-auth-* --filter=[HEAD^1]",
|
||||
"test": "turbo run test --concurrency=1 --filter=!@next-auth/pouchdb-adapter --filter=!@next-auth/upstash-redis-adapter --filter=!next-auth-* --filter=[HEAD^1]",
|
||||
"clean": "turbo run clean --no-cache",
|
||||
"dev:app": "turbo run dev --parallel --continue --filter=next-auth-app...",
|
||||
"dev:docs": "turbo run dev --filter=next-auth-docs",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@next-auth/mikro-orm-adapter",
|
||||
"version": "2.0.1",
|
||||
"version": "3.0.0",
|
||||
"description": "MikroORM adapter for next-auth.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
@@ -32,22 +32,22 @@
|
||||
"dist"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@mikro-orm/core": "^5.0.2",
|
||||
"@mikro-orm/core": "^5",
|
||||
"next-auth": "^4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mikro-orm/core": "^5.0.2",
|
||||
"@mikro-orm/sqlite": "^5.0.2",
|
||||
"@mikro-orm/core": "^5",
|
||||
"@mikro-orm/sqlite": "^5",
|
||||
"@next-auth/adapter-test": "workspace:*",
|
||||
"@next-auth/tsconfig": "workspace:*",
|
||||
"@types/uuid": "^8.3.3",
|
||||
"jest": "^27.4.3",
|
||||
"@types/uuid": ">=8",
|
||||
"jest": "^29",
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": "^9"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
OneToMany,
|
||||
Collection,
|
||||
ManyToOne,
|
||||
types,
|
||||
} from "@mikro-orm/core"
|
||||
|
||||
import type { DefaultAccount } from "next-auth"
|
||||
@@ -29,55 +30,56 @@ export class User implements RemoveIndex<AdapterUser> {
|
||||
@PrimaryKey()
|
||||
id: string = randomUUID()
|
||||
|
||||
@Property({ nullable: true })
|
||||
@Property({ type: types.string, nullable: true })
|
||||
name?: string
|
||||
|
||||
@Property({ nullable: true })
|
||||
@Property({ type: types.string, nullable: true })
|
||||
@Unique()
|
||||
email?: string
|
||||
|
||||
@Property({ type: "Date", nullable: true })
|
||||
@Property({ type: types.datetime, nullable: true })
|
||||
emailVerified: Date | null = null
|
||||
|
||||
@Property({ nullable: true })
|
||||
@Property({ type: types.string, nullable: true })
|
||||
image?: string
|
||||
|
||||
@OneToMany({
|
||||
entity: () => Session,
|
||||
mappedBy: (session) => session.user,
|
||||
entity: 'Session',
|
||||
mappedBy: (session: Session) => session.user,
|
||||
hidden: true,
|
||||
orphanRemoval: true,
|
||||
})
|
||||
sessions = new Collection<Session>(this)
|
||||
sessions = new Collection<Session, object>(this)
|
||||
|
||||
@OneToMany({
|
||||
entity: () => Account,
|
||||
mappedBy: (account) => account.user,
|
||||
entity: 'Account',
|
||||
mappedBy: (account: Account) => account.user,
|
||||
hidden: true,
|
||||
orphanRemoval: true,
|
||||
})
|
||||
accounts = new Collection<Account>(this)
|
||||
accounts = new Collection<Account, object>(this)
|
||||
}
|
||||
|
||||
@Entity()
|
||||
export class Session implements AdapterSession {
|
||||
@PrimaryKey()
|
||||
@Property({ type: types.string })
|
||||
id: string = randomUUID()
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => User,
|
||||
entity: 'User',
|
||||
hidden: true,
|
||||
onDelete: "cascade",
|
||||
})
|
||||
user!: User
|
||||
|
||||
@Property({ persist: false })
|
||||
@Property({ type: types.string, persist: false })
|
||||
userId!: string
|
||||
|
||||
@Property()
|
||||
@Property({ type: 'Date' })
|
||||
expires!: Date
|
||||
|
||||
@Property()
|
||||
@Property({ type: types.string })
|
||||
@Unique()
|
||||
sessionToken!: string
|
||||
}
|
||||
@@ -86,46 +88,47 @@ export class Session implements AdapterSession {
|
||||
@Unique({ properties: ["provider", "providerAccountId"] })
|
||||
export class Account implements RemoveIndex<DefaultAccount> {
|
||||
@PrimaryKey()
|
||||
@Property({ type: types.string })
|
||||
id: string = randomUUID()
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => User,
|
||||
entity: 'User',
|
||||
hidden: true,
|
||||
onDelete: "cascade",
|
||||
})
|
||||
user!: User
|
||||
|
||||
@Property({ persist: false })
|
||||
@Property({ type: types.string, persist: false })
|
||||
userId!: string
|
||||
|
||||
@Enum()
|
||||
@Property({ type: types.string })
|
||||
type!: ProviderType
|
||||
|
||||
@Property()
|
||||
@Property({ type: types.string })
|
||||
provider!: string
|
||||
|
||||
@Property()
|
||||
@Property({ type: types.string })
|
||||
providerAccountId!: string
|
||||
|
||||
@Property({ nullable: true })
|
||||
@Property({ type: types.string, nullable: true })
|
||||
refresh_token?: string
|
||||
|
||||
@Property({ nullable: true })
|
||||
@Property({ type: types.string, nullable: true })
|
||||
access_token?: string
|
||||
|
||||
@Property({ nullable: true })
|
||||
@Property({ type: types.integer, nullable: true })
|
||||
expires_at?: number
|
||||
|
||||
@Property({ nullable: true })
|
||||
@Property({ type: types.string, nullable: true })
|
||||
token_type?: string
|
||||
|
||||
@Property({ nullable: true })
|
||||
@Property({ type: types.string, nullable: true })
|
||||
scope?: string
|
||||
|
||||
@Property({ nullable: true })
|
||||
@Property({ type: types.text, nullable: true })
|
||||
id_token?: string
|
||||
|
||||
@Property({ nullable: true })
|
||||
@Property({ type: types.string, nullable: true })
|
||||
session_state?: string
|
||||
}
|
||||
|
||||
@@ -133,12 +136,12 @@ export class Account implements RemoveIndex<DefaultAccount> {
|
||||
@Unique({ properties: ["token", "identifier"] })
|
||||
export class VerificationToken implements AdapterVerificationToken {
|
||||
@PrimaryKey()
|
||||
@Property()
|
||||
@Property({ type: types.string })
|
||||
token!: string
|
||||
|
||||
@Property()
|
||||
@Property({ type: 'Date' })
|
||||
expires!: Date
|
||||
|
||||
@Property()
|
||||
@Property({ type: types.string })
|
||||
identifier!: string
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { MikroORM, wrap } from "@mikro-orm/core"
|
||||
|
||||
import * as defaultEntities from "./entities"
|
||||
|
||||
export * as defaultEntities from "./entities"
|
||||
export { defaultEntities }
|
||||
|
||||
/**
|
||||
* The MikroORM adapter accepts a MikroORM configuration and returns a NextAuth adapter.
|
||||
|
||||
@@ -0,0 +1,591 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`run migrations: createSchemaSQL 1`] = `
|
||||
"pragma foreign_keys = off;
|
||||
|
||||
create table \`user\` (\`id\` text not null, \`name\` text null, \`email\` text null, \`email_verified\` datetime null, \`image\` text null, primary key (\`id\`));
|
||||
create unique index \`user_email_unique\` on \`user\` (\`email\`);
|
||||
|
||||
create table \`session\` (\`id\` text not null, \`user_id\` text not null, \`expires\` datetime not null, \`session_token\` text not null, constraint \`session_user_id_foreign\` foreign key(\`user_id\`) references \`user\`(\`id\`) on delete cascade on update cascade, primary key (\`id\`));
|
||||
create index \`session_user_id_index\` on \`session\` (\`user_id\`);
|
||||
create unique index \`session_session_token_unique\` on \`session\` (\`session_token\`);
|
||||
|
||||
create table \`account\` (\`id\` text not null, \`user_id\` text not null, \`type\` text not null, \`provider\` text not null, \`provider_account_id\` text not null, \`refresh_token\` text null, \`access_token\` text null, \`expires_at\` integer null, \`token_type\` text null, \`scope\` text null, \`id_token\` text null, \`session_state\` text null, constraint \`account_user_id_foreign\` foreign key(\`user_id\`) references \`user\`(\`id\`) on delete cascade on update cascade, primary key (\`id\`));
|
||||
create index \`account_user_id_index\` on \`account\` (\`user_id\`);
|
||||
create unique index \`account_provider_provider_account_id_unique\` on \`account\` (\`provider\`, \`provider_account_id\`);
|
||||
|
||||
create table \`verification_token\` (\`token\` text not null, \`expires\` datetime not null, \`identifier\` text not null, primary key (\`token\`));
|
||||
create unique index \`verification_token_token_identifier_unique\` on \`verification_token\` (\`token\`, \`identifier\`);
|
||||
|
||||
pragma foreign_keys = on;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`run migrations: targetSchema 1`] = `
|
||||
{
|
||||
"name": undefined,
|
||||
"namespaces": [],
|
||||
"tables": [
|
||||
{
|
||||
"checks": [],
|
||||
"columns": {
|
||||
"email": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "email",
|
||||
"nullable": true,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"email_verified": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": 0,
|
||||
"mappedType": "datetime",
|
||||
"name": "email_verified",
|
||||
"nullable": true,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "datetime",
|
||||
"unsigned": false,
|
||||
},
|
||||
"id": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "id",
|
||||
"nullable": false,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"image": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "image",
|
||||
"nullable": true,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"name": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "name",
|
||||
"nullable": true,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
},
|
||||
"comment": undefined,
|
||||
"foreignKeys": {},
|
||||
"indexes": [
|
||||
{
|
||||
"columnNames": [
|
||||
"email",
|
||||
],
|
||||
"composite": false,
|
||||
"keyName": "user_email_unique",
|
||||
"primary": false,
|
||||
"unique": true,
|
||||
},
|
||||
{
|
||||
"columnNames": [
|
||||
"id",
|
||||
],
|
||||
"composite": false,
|
||||
"expression": undefined,
|
||||
"keyName": "primary",
|
||||
"primary": true,
|
||||
"type": undefined,
|
||||
"unique": true,
|
||||
},
|
||||
],
|
||||
"name": "user",
|
||||
"schema": undefined,
|
||||
},
|
||||
{
|
||||
"checks": [],
|
||||
"columns": {
|
||||
"expires": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": 0,
|
||||
"mappedType": "datetime",
|
||||
"name": "expires",
|
||||
"nullable": false,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "datetime",
|
||||
"unsigned": false,
|
||||
},
|
||||
"id": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "id",
|
||||
"nullable": false,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"session_token": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "session_token",
|
||||
"nullable": false,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"user_id": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "user_id",
|
||||
"nullable": false,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
},
|
||||
"comment": undefined,
|
||||
"foreignKeys": {
|
||||
"session_user_id_foreign": {
|
||||
"columnNames": [
|
||||
"user_id",
|
||||
],
|
||||
"constraintName": "session_user_id_foreign",
|
||||
"deleteRule": "cascade",
|
||||
"localTableName": "session",
|
||||
"referencedColumnNames": [
|
||||
"id",
|
||||
],
|
||||
"referencedTableName": "user",
|
||||
"updateRule": "cascade",
|
||||
},
|
||||
},
|
||||
"indexes": [
|
||||
{
|
||||
"columnNames": [
|
||||
"user_id",
|
||||
],
|
||||
"composite": false,
|
||||
"keyName": "session_user_id_index",
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
},
|
||||
{
|
||||
"columnNames": [
|
||||
"session_token",
|
||||
],
|
||||
"composite": false,
|
||||
"keyName": "session_session_token_unique",
|
||||
"primary": false,
|
||||
"unique": true,
|
||||
},
|
||||
{
|
||||
"columnNames": [
|
||||
"id",
|
||||
],
|
||||
"composite": false,
|
||||
"expression": undefined,
|
||||
"keyName": "primary",
|
||||
"primary": true,
|
||||
"type": undefined,
|
||||
"unique": true,
|
||||
},
|
||||
],
|
||||
"name": "session",
|
||||
"schema": undefined,
|
||||
},
|
||||
{
|
||||
"checks": [],
|
||||
"columns": {
|
||||
"access_token": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "access_token",
|
||||
"nullable": true,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"expires_at": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "integer",
|
||||
"name": "expires_at",
|
||||
"nullable": true,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "integer",
|
||||
"unsigned": false,
|
||||
},
|
||||
"id": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "id",
|
||||
"nullable": false,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"id_token": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "id_token",
|
||||
"nullable": true,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"provider": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "provider",
|
||||
"nullable": false,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"provider_account_id": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "provider_account_id",
|
||||
"nullable": false,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"refresh_token": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "refresh_token",
|
||||
"nullable": true,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"scope": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "scope",
|
||||
"nullable": true,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"session_state": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "session_state",
|
||||
"nullable": true,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"token_type": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "token_type",
|
||||
"nullable": true,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"type": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "type",
|
||||
"nullable": false,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"user_id": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "user_id",
|
||||
"nullable": false,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
},
|
||||
"comment": undefined,
|
||||
"foreignKeys": {
|
||||
"account_user_id_foreign": {
|
||||
"columnNames": [
|
||||
"user_id",
|
||||
],
|
||||
"constraintName": "account_user_id_foreign",
|
||||
"deleteRule": "cascade",
|
||||
"localTableName": "account",
|
||||
"referencedColumnNames": [
|
||||
"id",
|
||||
],
|
||||
"referencedTableName": "user",
|
||||
"updateRule": "cascade",
|
||||
},
|
||||
},
|
||||
"indexes": [
|
||||
{
|
||||
"columnNames": [
|
||||
"user_id",
|
||||
],
|
||||
"composite": false,
|
||||
"keyName": "account_user_id_index",
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
},
|
||||
{
|
||||
"columnNames": [
|
||||
"provider",
|
||||
"provider_account_id",
|
||||
],
|
||||
"composite": true,
|
||||
"expression": undefined,
|
||||
"keyName": "account_provider_provider_account_id_unique",
|
||||
"primary": false,
|
||||
"type": undefined,
|
||||
"unique": true,
|
||||
},
|
||||
{
|
||||
"columnNames": [
|
||||
"id",
|
||||
],
|
||||
"composite": false,
|
||||
"expression": undefined,
|
||||
"keyName": "primary",
|
||||
"primary": true,
|
||||
"type": undefined,
|
||||
"unique": true,
|
||||
},
|
||||
],
|
||||
"name": "account",
|
||||
"schema": undefined,
|
||||
},
|
||||
{
|
||||
"checks": [],
|
||||
"columns": {
|
||||
"expires": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": 0,
|
||||
"mappedType": "datetime",
|
||||
"name": "expires",
|
||||
"nullable": false,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "datetime",
|
||||
"unsigned": false,
|
||||
},
|
||||
"identifier": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "identifier",
|
||||
"nullable": false,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
"token": {
|
||||
"autoincrement": false,
|
||||
"comment": undefined,
|
||||
"default": undefined,
|
||||
"enumItems": undefined,
|
||||
"extra": undefined,
|
||||
"length": undefined,
|
||||
"mappedType": "text",
|
||||
"name": "token",
|
||||
"nullable": false,
|
||||
"precision": undefined,
|
||||
"primary": false,
|
||||
"scale": undefined,
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
},
|
||||
},
|
||||
"comment": undefined,
|
||||
"foreignKeys": {},
|
||||
"indexes": [
|
||||
{
|
||||
"columnNames": [
|
||||
"token",
|
||||
"identifier",
|
||||
],
|
||||
"composite": true,
|
||||
"expression": undefined,
|
||||
"keyName": "verification_token_token_identifier_unique",
|
||||
"primary": false,
|
||||
"type": undefined,
|
||||
"unique": true,
|
||||
},
|
||||
{
|
||||
"columnNames": [
|
||||
"token",
|
||||
],
|
||||
"composite": false,
|
||||
"expression": undefined,
|
||||
"keyName": "primary",
|
||||
"primary": true,
|
||||
"type": undefined,
|
||||
"unique": true,
|
||||
},
|
||||
],
|
||||
"name": "verification_token",
|
||||
"schema": undefined,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
@@ -1,10 +1,69 @@
|
||||
import type { Options } from "@mikro-orm/core"
|
||||
import { Options, types } from "@mikro-orm/core"
|
||||
import type { SqliteDriver } from "@mikro-orm/sqlite"
|
||||
|
||||
import { MikroORM, wrap } from "@mikro-orm/core"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import { MikroOrmAdapter, defaultEntities } from "../src"
|
||||
import { User, VeryImportantEntity } from "./testEntities"
|
||||
import {
|
||||
Cascade,
|
||||
Collection,
|
||||
Entity,
|
||||
OneToMany,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
Unique,
|
||||
} from "@mikro-orm/core"
|
||||
import { randomUUID } from "@next-auth/adapter-test"
|
||||
|
||||
@Entity()
|
||||
export class User implements defaultEntities.User {
|
||||
@PrimaryKey()
|
||||
@Property({ type: types.string })
|
||||
id: string = randomUUID()
|
||||
|
||||
@Property({ type: types.string, nullable: true })
|
||||
name?: string
|
||||
|
||||
@Property({ type: types.string, nullable: true })
|
||||
@Unique()
|
||||
email?: string
|
||||
|
||||
@Property({ type: 'Date', nullable: true })
|
||||
emailVerified: Date | null = null
|
||||
|
||||
@Property({ type: types.string, nullable: true })
|
||||
image?: string
|
||||
|
||||
@OneToMany({
|
||||
entity: 'Session',
|
||||
mappedBy: (session: defaultEntities.Session) => session.user,
|
||||
hidden: true,
|
||||
orphanRemoval: true,
|
||||
cascade: [Cascade.ALL],
|
||||
})
|
||||
sessions = new Collection<defaultEntities.Session>(this)
|
||||
|
||||
@OneToMany({
|
||||
entity: 'Account',
|
||||
mappedBy: (account: defaultEntities.Account) => account.user,
|
||||
hidden: true,
|
||||
orphanRemoval: true,
|
||||
cascade: [Cascade.ALL],
|
||||
})
|
||||
accounts = new Collection<defaultEntities.Account>(this)
|
||||
|
||||
@Property({ type: types.string, hidden: true })
|
||||
role = "ADMIN"
|
||||
}
|
||||
|
||||
@Entity()
|
||||
export class VeryImportantEntity {
|
||||
@PrimaryKey()
|
||||
@Property({ type: types.string })
|
||||
id: string = randomUUID()
|
||||
|
||||
@Property({ type: types.boolean })
|
||||
important = true
|
||||
}
|
||||
|
||||
let _init: MikroORM
|
||||
|
||||
28
packages/adapter-mikro-orm/tests/schema.test.ts
Normal file
28
packages/adapter-mikro-orm/tests/schema.test.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { MikroORM, Options } from "@mikro-orm/core";
|
||||
import { SqliteDriver } from "@mikro-orm/sqlite";
|
||||
import { defaultEntities } from "../src";
|
||||
|
||||
const config: Options<SqliteDriver> = {
|
||||
dbName: "./db.sqlite",
|
||||
type: "sqlite",
|
||||
entities: [
|
||||
defaultEntities.User,
|
||||
defaultEntities.Account,
|
||||
defaultEntities.Session,
|
||||
defaultEntities.VerificationToken,
|
||||
],
|
||||
}
|
||||
|
||||
it("run migrations", async () => {
|
||||
const orm = await MikroORM.init(config)
|
||||
await orm.getSchemaGenerator().dropSchema()
|
||||
|
||||
const createSchemaSQL = await orm.getSchemaGenerator().getCreateSchemaSQL()
|
||||
expect(createSchemaSQL).toMatchSnapshot('createSchemaSQL')
|
||||
|
||||
const targetSchema = await orm.getSchemaGenerator().getTargetSchema()
|
||||
expect(targetSchema).toMatchSnapshot('targetSchema')
|
||||
|
||||
await orm.getSchemaGenerator().dropSchema()
|
||||
await orm.close().catch(() => null)
|
||||
})
|
||||
@@ -1,61 +0,0 @@
|
||||
import {
|
||||
Cascade,
|
||||
Collection,
|
||||
Entity,
|
||||
OneToMany,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
Unique,
|
||||
} from "@mikro-orm/core"
|
||||
import { randomUUID } from "@next-auth/adapter-test"
|
||||
import type { defaultEntities } from "../src"
|
||||
import { Account, Session } from "../src/entities"
|
||||
|
||||
@Entity()
|
||||
export class User implements defaultEntities.User {
|
||||
@PrimaryKey()
|
||||
id: string = randomUUID()
|
||||
|
||||
@Property({ nullable: true })
|
||||
name?: string
|
||||
|
||||
@Property({ nullable: true })
|
||||
@Unique()
|
||||
email?: string
|
||||
|
||||
@Property({ type: "Date", nullable: true })
|
||||
emailVerified: Date | null = null
|
||||
|
||||
@Property({ nullable: true })
|
||||
image?: string
|
||||
|
||||
@OneToMany({
|
||||
entity: () => Session,
|
||||
mappedBy: (session) => session.user,
|
||||
hidden: true,
|
||||
orphanRemoval: true,
|
||||
cascade: [Cascade.ALL],
|
||||
})
|
||||
sessions = new Collection<Session>(this)
|
||||
|
||||
@OneToMany({
|
||||
entity: () => Account,
|
||||
mappedBy: (account) => account.user,
|
||||
hidden: true,
|
||||
orphanRemoval: true,
|
||||
cascade: [Cascade.ALL],
|
||||
})
|
||||
accounts = new Collection<Account>(this)
|
||||
|
||||
@Property({ hidden: true })
|
||||
role = "ADMIN"
|
||||
}
|
||||
|
||||
@Entity()
|
||||
export class VeryImportantEntity {
|
||||
@PrimaryKey()
|
||||
id: string = randomUUID()
|
||||
|
||||
@Property()
|
||||
important = true
|
||||
}
|
||||
@@ -5,4 +5,4 @@
|
||||
"./*.js",
|
||||
"./*.d.ts",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,5 +8,6 @@
|
||||
"outDir": "dist",
|
||||
"stripInternal": true
|
||||
},
|
||||
"exclude": ["tests", "dist", "jest.config.js"]
|
||||
"include": ["src"],
|
||||
"exclude": ["dist", "test", "node_modules"]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@next-auth/mongodb-adapter",
|
||||
"version": "1.0.4",
|
||||
"version": "1.1.0",
|
||||
"description": "mongoDB adapter for next-auth.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@next-auth/upstash-redis-adapter",
|
||||
"version": "3.0.1",
|
||||
"version": "3.0.2",
|
||||
"description": "Upstash adapter for next-auth. It uses Upstash's connectionless (HTTP based) Redis client.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
|
||||
@@ -165,13 +165,20 @@ export function UpstashRedisAdapter(
|
||||
},
|
||||
async createVerificationToken(verificationToken) {
|
||||
await setObjectAsJson(
|
||||
verificationTokenKeyPrefix + verificationToken.identifier,
|
||||
verificationTokenKeyPrefix +
|
||||
verificationToken.identifier +
|
||||
":" +
|
||||
verificationToken.token,
|
||||
verificationToken
|
||||
)
|
||||
return verificationToken
|
||||
},
|
||||
async useVerificationToken(verificationToken) {
|
||||
const tokenKey = verificationTokenKeyPrefix + verificationToken.identifier
|
||||
const tokenKey =
|
||||
verificationTokenKeyPrefix +
|
||||
verificationToken.identifier +
|
||||
":" +
|
||||
verificationToken.token
|
||||
|
||||
const token = await client.get<VerificationToken>(tokenKey)
|
||||
if (!token) return null
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "next-auth",
|
||||
"version": "4.10.3",
|
||||
"version": "4.12.0",
|
||||
"description": "Authentication for Next.js",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/next-auth.git",
|
||||
@@ -69,8 +69,8 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.16.3",
|
||||
"@panva/hkdf": "^1.0.1",
|
||||
"cookie": "^0.4.1",
|
||||
"jose": "^4.3.7",
|
||||
"cookie": "^0.5.0",
|
||||
"jose": "^4.9.3",
|
||||
"oauth": "^0.9.15",
|
||||
"openid-client": "^5.1.0",
|
||||
"preact": "^10.6.3",
|
||||
@@ -78,6 +78,7 @@
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"next": "12.2.5",
|
||||
"nodemailer": "^6.6.5",
|
||||
"react": "^17.0.2 || ^18",
|
||||
"react-dom": "^17.0.2 || ^18"
|
||||
@@ -118,7 +119,7 @@
|
||||
"jest-environment-jsdom": "^28.1.1",
|
||||
"jest-watch-typeahead": "^1.1.0",
|
||||
"msw": "^0.42.3",
|
||||
"next": "12.2.0",
|
||||
"next": "12.2.5",
|
||||
"postcss": "^8.4.14",
|
||||
"postcss-cli": "^9.1.0",
|
||||
"postcss-nested": "^5.0.6",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { randomBytes, randomUUID } from "crypto"
|
||||
import { NextAuthOptions } from ".."
|
||||
import logger from "../utils/logger"
|
||||
import parseUrl from "../utils/parse-url"
|
||||
@@ -86,6 +87,10 @@ export async function init({
|
||||
strategy: userOptions.adapter ? "database" : "jwt",
|
||||
maxAge,
|
||||
updateAge: 24 * 60 * 60,
|
||||
generateSessionToken: () => {
|
||||
// Use `randomUUID` if available. (Node 15.6+)
|
||||
return randomUUID?.() ?? randomBytes(32).toString("hex")
|
||||
},
|
||||
...userOptions.session,
|
||||
},
|
||||
// JWT options
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { randomBytes, randomUUID } from "crypto"
|
||||
import { AccountNotLinkedError } from "../errors"
|
||||
import { fromDate } from "./utils"
|
||||
|
||||
@@ -37,7 +36,7 @@ export default async function callbackHandler(params: {
|
||||
adapter,
|
||||
jwt,
|
||||
events,
|
||||
session: { strategy: sessionStrategy },
|
||||
session: { strategy: sessionStrategy, generateSessionToken },
|
||||
} = options
|
||||
|
||||
// If no adapter is configured then we don't have a database and cannot
|
||||
@@ -219,8 +218,3 @@ export default async function callbackHandler(params: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateSessionToken() {
|
||||
// Use `randomUUID` if available. (Node 15.6++)
|
||||
return randomUUID?.() ?? randomBytes(32).toString("hex")
|
||||
}
|
||||
|
||||
@@ -468,6 +468,13 @@ export interface SessionOptions {
|
||||
* @default 86400 // 1 day
|
||||
*/
|
||||
updateAge: number
|
||||
/**
|
||||
* Generate a custom session token for database-based sessions.
|
||||
* By default, a random UUID or string is generated depending on the Node.js version.
|
||||
* However, you can specify your own custom string (such as CUID) to be used.
|
||||
* @default `randomUUID` or `randomBytes.toHex` depending on the Node.js version
|
||||
*/
|
||||
generateSessionToken: () => string
|
||||
}
|
||||
|
||||
export interface DefaultUser {
|
||||
|
||||
@@ -106,12 +106,13 @@ async function handleMiddleware(
|
||||
const signInPage = options?.pages?.signIn ?? "/api/auth/signin"
|
||||
const errorPage = options?.pages?.error ?? "/api/auth/error"
|
||||
const basePath = parseUrl(process.env.NEXTAUTH_URL).path
|
||||
const publicPaths = [signInPage, errorPage, "/_next", "/favicon.ico"]
|
||||
const publicPaths = ["/_next", "/favicon.ico"]
|
||||
|
||||
// Avoid infinite redirects/invalid response
|
||||
// on paths that never require authentication
|
||||
if (
|
||||
pathname.startsWith(basePath) ||
|
||||
[signInPage, errorPage].includes(pathname) ||
|
||||
publicPaths.some((p) => pathname.startsWith(p))
|
||||
) {
|
||||
return
|
||||
|
||||
40
packages/next-auth/tests/middleware.test.ts
Normal file
40
packages/next-auth/tests/middleware.test.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { NextMiddleware } from "next/server"
|
||||
import { NextAuthMiddlewareOptions, withAuth } from "../next/middleware"
|
||||
|
||||
it("should not match pages as public paths", async () => {
|
||||
const options: NextAuthMiddlewareOptions = {
|
||||
pages: {
|
||||
signIn: "/",
|
||||
error: "/"
|
||||
},
|
||||
secret: "secret"
|
||||
}
|
||||
|
||||
const nextUrl: any = {
|
||||
pathname: "/protected/pathA",
|
||||
search: "",
|
||||
origin: "http://127.0.0.1"
|
||||
}
|
||||
const req: any = { nextUrl, headers: { authorization: "" } }
|
||||
|
||||
const handleMiddleware = withAuth(options) as NextMiddleware
|
||||
const res = await handleMiddleware(req, null)
|
||||
expect(res).toBeDefined()
|
||||
expect(res.status).toBe(307)
|
||||
})
|
||||
|
||||
it("should not redirect on public paths", async () => {
|
||||
const options: NextAuthMiddlewareOptions = {
|
||||
secret: "secret"
|
||||
}
|
||||
const nextUrl: any = {
|
||||
pathname: "/_next/foo",
|
||||
search: "",
|
||||
origin: "http://127.0.0.1"
|
||||
}
|
||||
const req: any = { nextUrl, headers: { authorization: "" } }
|
||||
|
||||
const handleMiddleware = withAuth(options) as NextMiddleware
|
||||
const res = await handleMiddleware(req, null)
|
||||
expect(res).toBeUndefined()
|
||||
})
|
||||
1246
pnpm-lock.yaml
generated
1246
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user