├── .babelrc.js
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── dynamodb.yaml
│ ├── faunadb.yaml
│ ├── firebase.yaml
│ ├── mongodb.yaml
│ ├── pouchdb.yaml
│ ├── prisma.yaml
│ ├── typeorm-legacy.yaml
│ └── upstash-redis.yaml
├── PULL_REQUEST_TEMPLATE.md
├── labeler.yml
├── stale.yml
└── workflows
│ ├── codeql-analysis.yml
│ ├── labeler.yml
│ └── release.yml
├── .gitignore
├── .husky
├── .gitignore
└── pre-commit
├── .nvmrc
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── basic-tests.ts
├── jest.config.js
├── lerna.json
├── package.json
├── packages
├── dgraph
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── client.ts
│ │ ├── graphql
│ │ │ ├── fragments.ts
│ │ │ └── schema.gql
│ │ ├── index.ts
│ │ └── utils.ts
│ ├── tests
│ │ ├── index.test.ts
│ │ ├── private.key
│ │ ├── public.key
│ │ └── test.sh
│ └── tsconfig.json
├── dynamodb
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── jest-dynamodb-config.js
│ ├── jest.config.js
│ ├── logo.png
│ ├── package.json
│ ├── src
│ │ ├── index.ts
│ │ └── utils.ts
│ ├── tests
│ │ ├── custom.test.ts
│ │ ├── format.test.ts
│ │ └── index.test.ts
│ └── tsconfig.json
├── fauna
│ ├── .babelrc.js
│ ├── .fauna-migrate.js
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── fauna
│ │ ├── resources
│ │ │ ├── collections
│ │ │ │ ├── accounts.fql
│ │ │ │ ├── sessions.fql
│ │ │ │ ├── users.fql
│ │ │ │ └── verification_tokens.fql
│ │ │ └── indexes
│ │ │ │ ├── account_by_provider_and_provider_account_id.fql
│ │ │ │ ├── accounts_by_user_id.fql
│ │ │ │ ├── session_by_session_token.fql
│ │ │ │ ├── sessions_by_user_id.fql
│ │ │ │ ├── user_by_email.fql
│ │ │ │ └── verification_token_by_identifier_and_token.fql
│ │ └── schema.fql
│ ├── jest.config.js
│ ├── logo.svg
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ ├── tests
│ │ ├── index.test.ts
│ │ └── test.sh
│ └── tsconfig.json
├── firebase
│ ├── .firebaserc
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── firebase.json
│ ├── jest.config.js
│ ├── logo.svg
│ ├── package.json
│ ├── src
│ │ ├── index.ts
│ │ └── utils.ts
│ ├── tests
│ │ └── index.test.ts
│ └── tsconfig.json
├── mikro-orm
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── jest.config.js
│ ├── logo.svg
│ ├── package.json
│ ├── src
│ │ ├── entities.ts
│ │ └── index.ts
│ ├── tests
│ │ ├── index.test.ts
│ │ └── testEntities.ts
│ └── tsconfig.json
├── mongodb
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── jest.config.js
│ ├── logo.svg
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ ├── tests
│ │ ├── custom.test.ts
│ │ ├── index.test.ts
│ │ └── test.sh
│ └── tsconfig.json
├── neo4j
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── jest.config.js
│ ├── logo.svg
│ ├── package.json
│ ├── src
│ │ ├── index.ts
│ │ └── utils.ts
│ ├── tests
│ │ ├── index.test.ts
│ │ ├── resources
│ │ │ └── statements.ts
│ │ └── test.sh
│ └── tsconfig.json
├── pouchdb
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── jest.config.js
│ ├── logo.svg
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ ├── tests
│ │ └── index.test.ts
│ └── tsconfig.json
├── prisma
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── jest.config.js
│ ├── logo.svg
│ ├── package.json
│ ├── prisma
│ │ ├── custom.prisma
│ │ ├── migrations
│ │ │ └── migration_lock.toml
│ │ └── schema.prisma
│ ├── src
│ │ └── index.ts
│ ├── tests
│ │ └── index.test.ts
│ └── tsconfig.json
├── sequelize
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── jest.config.js
│ ├── logo.svg
│ ├── package.json
│ ├── src
│ │ ├── index.ts
│ │ └── models.ts
│ ├── tests
│ │ └── index.test.ts
│ └── tsconfig.json
├── typeorm-legacy
│ ├── .dockerignore
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── docs
│ │ └── tutorials
│ │ │ └── typeorm-custom-models.md
│ ├── jest.config.js
│ ├── logo.png
│ ├── package.json
│ ├── src
│ │ ├── entities.ts
│ │ ├── index.ts
│ │ └── utils.ts
│ ├── tests
│ │ ├── custom-entities.ts
│ │ ├── helpers.ts
│ │ ├── index.test.ts
│ │ ├── init.sh
│ │ ├── mysql
│ │ │ ├── index.custom.test.ts
│ │ │ ├── index.test.ts
│ │ │ └── test.sh
│ │ ├── postgresql
│ │ │ ├── index.custom.test.ts
│ │ │ ├── index.test.ts
│ │ │ └── test.sh
│ │ ├── sqlite
│ │ │ ├── index.custom.test.ts
│ │ │ ├── index.test.ts
│ │ │ └── test.sh
│ │ └── test.sh
│ └── tsconfig.json
└── upstash-redis
│ ├── .env.example
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── jest.config.js
│ ├── logo.svg
│ ├── package.json
│ ├── src
│ └── index.ts
│ ├── tests
│ └── index.test.ts
│ └── tsconfig.json
├── tsconfig.json
└── yarn.lock
/.babelrc.js:
--------------------------------------------------------------------------------
1 | // We aim to have the same support as Next.js
2 | // https://nextjs.org/docs/getting-started#system-requirements
3 | // https://nextjs.org/docs/basic-features/supported-browsers-features
4 |
5 | module.exports = {
6 | presets: [["@babel/preset-env", { targets: { node: "12" } }]],
7 | plugins: ["@babel/plugin-transform-runtime"],
8 | comments: false,
9 | }
10 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # https://docs.github.com/en/github/administering-a-repository/displaying-a-sponsor-button-in-your-repository
2 |
3 | open_collective: nextauth
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/dynamodb.yaml:
--------------------------------------------------------------------------------
1 | name: DynamoDB
2 | description: File a support request for the DynamoDB adapter
3 | labels: dynamodb
4 |
5 | # note: markdown sections will NOT appear as part of the issue as per documentation, rather they provide context to the user
6 | # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#markdown
7 |
8 |
9 | body:
10 | - type: markdown
11 | attributes:
12 | value: |
13 | Thanks for taking the time to fill out this issue!
14 | ### Important :exclamation:
15 | Please help us maintain this project more efficiently! Before creating the issue make sure you shouldn't be creating it in one the below repos instead:
16 | - Core related: https://github.com/nextauthjs/next-auth
17 | - Docs related: https://github.com/nextauthjs/docs
18 |
19 | If you are in the correct repo, then proceed by providing the following information:
20 | - type: input
21 | id: title
22 | attributes:
23 | label: Title
24 | validations:
25 | required: true
26 | - type: textarea
27 | id: reproduction
28 | attributes:
29 | label: How to reproduce ☕️
30 | description: Please provide a link or code snippets to a minimal reproduction of the bug
31 | validations:
32 | required: true
33 | - type: markdown
34 | attributes:
35 | value: |
36 | We encourage you to use one of the templates set up on **CodeSandbox** to reproduce your issue:
37 | - [`next-auth-example`](https://codesandbox.io/s/next-auth-example-1kktb)
38 | - [`next-auth-typescript-example`](https://codesandbox.io/s/next-auth-typescript-example-se32w)
39 |
40 | 🚧 – _If you don't provide any way to reproduce the bug, the issue is at risk of being closed._
41 |
42 | - type: textarea
43 | id: description
44 | attributes:
45 | label: Your question/bug report 📓
46 | description: Please provide a more in-depth description of your request.
47 | validations:
48 | required: true
49 | - type: dropdown
50 | id: contributing
51 | attributes:
52 | label: Contributing 🙌🏽
53 | description: Are you willing to open a PR for this?
54 | multiple: false
55 | options:
56 | - "Yes, I am"
57 | - "No, I'm afraid I cannot help regarding this"
58 | validations:
59 | required: true
60 | - type: markdown
61 | attributes:
62 | value: |
63 | It takes a lot of work 🏋🏻♀️ maintaining a library like `next-auth`; any contribution is more than welcome 💚
64 |
65 |
66 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/faunadb.yaml:
--------------------------------------------------------------------------------
1 | name: FaunaDB
2 | description: File a support request for the FaunaDB adapter
3 | labels: fauna
4 |
5 | # note: markdown sections will NOT appear as part of the issue as per documentation, rather they provide context to the user
6 | # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#markdown
7 |
8 |
9 | body:
10 | - type: markdown
11 | attributes:
12 | value: |
13 | Thanks for taking the time to fill out this issue!
14 | ### Important :exclamation:
15 | Please help us maintain this project more efficiently! Before creating the issue make sure you shouldn't be creating it in one the below repos instead:
16 | - Core related: https://github.com/nextauthjs/next-auth
17 | - Docs related: https://github.com/nextauthjs/docs
18 |
19 | If you are in the correct repo, then proceed by providing the following information:
20 | - type: input
21 | id: title
22 | attributes:
23 | label: Title
24 | validations:
25 | required: true
26 | - type: textarea
27 | id: reproduction
28 | attributes:
29 | label: How to reproduce ☕️
30 | description: Please provide a link or code snippets to a minimal reproduction of the bug
31 | validations:
32 | required: true
33 | - type: markdown
34 | attributes:
35 | value: |
36 | We encourage you to use one of the templates set up on **CodeSandbox** to reproduce your issue:
37 | - [`next-auth-example`](https://codesandbox.io/s/next-auth-example-1kktb)
38 | - [`next-auth-typescript-example`](https://codesandbox.io/s/next-auth-typescript-example-se32w)
39 |
40 | 🚧 – _If you don't provide any way to reproduce the bug, the issue is at risk of being closed._
41 |
42 | - type: textarea
43 | id: description
44 | attributes:
45 | label: Your question/bug report 📓
46 | description: Please provide a more in-depth description of your request.
47 | validations:
48 | required: true
49 | - type: dropdown
50 | id: contributing
51 | attributes:
52 | label: Contributing 🙌🏽
53 | description: Are you willing to open a PR for this?
54 | multiple: false
55 | options:
56 | - "Yes, I am"
57 | - "No, I'm afraid I cannot help regarding this"
58 | validations:
59 | required: true
60 | - type: markdown
61 | attributes:
62 | value: |
63 | It takes a lot of work 🏋🏻♀️ maintaining a library like `next-auth`; any contribution is more than welcome 💚
64 |
65 |
66 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/firebase.yaml:
--------------------------------------------------------------------------------
1 | name: Firebase
2 | description: File a support request for the Firebase adapter
3 | labels: firebase
4 |
5 | # note: markdown sections will NOT appear as part of the issue as per documentation, rather they provide context to the user
6 | # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#markdown
7 |
8 |
9 | body:
10 | - type: markdown
11 | attributes:
12 | value: |
13 | Thanks for taking the time to fill out this issue!
14 | ### Important :exclamation:
15 | Please help us maintain this project more efficiently! Before creating the issue make sure you shouldn't be creating it in one the below repos instead:
16 | - Core related: https://github.com/nextauthjs/next-auth
17 | - Docs related: https://github.com/nextauthjs/docs
18 |
19 | If you are in the correct repo, then proceed by providing the following information:
20 | - type: input
21 | id: title
22 | attributes:
23 | label: Title
24 | validations:
25 | required: true
26 | - type: textarea
27 | id: reproduction
28 | attributes:
29 | label: How to reproduce ☕️
30 | description: Please provide a link or code snippets to a minimal reproduction of the bug
31 | validations:
32 | required: true
33 | - type: markdown
34 | attributes:
35 | value: |
36 | We encourage you to use one of the templates set up on **CodeSandbox** to reproduce your issue:
37 | - [`next-auth-example`](https://codesandbox.io/s/next-auth-example-1kktb)
38 | - [`next-auth-typescript-example`](https://codesandbox.io/s/next-auth-typescript-example-se32w)
39 |
40 | 🚧 – _If you don't provide any way to reproduce the bug, the issue is at risk of being closed._
41 |
42 | - type: textarea
43 | id: description
44 | attributes:
45 | label: Your question/bug report 📓
46 | description: Please provide a more in-depth description of your request.
47 | validations:
48 | required: true
49 | - type: dropdown
50 | id: contributing
51 | attributes:
52 | label: Contributing 🙌🏽
53 | description: Are you willing to open a PR for this?
54 | multiple: false
55 | options:
56 | - "Yes, I am"
57 | - "No, I'm afraid I cannot help regarding this"
58 | validations:
59 | required: true
60 | - type: markdown
61 | attributes:
62 | value: |
63 | It takes a lot of work 🏋🏻♀️ maintaining a library like `next-auth`; any contribution is more than welcome 💚
64 |
65 |
66 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/mongodb.yaml:
--------------------------------------------------------------------------------
1 | name: MongoDB
2 | description: File a support request for the MongoDB adapter
3 | labels: mongodb
4 |
5 | # note: markdown sections will NOT appear as part of the issue as per documentation, rather they provide context to the user
6 | # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#markdown
7 |
8 |
9 | body:
10 | - type: markdown
11 | attributes:
12 | value: |
13 | Thanks for taking the time to fill out this issue!
14 | ### Important :exclamation:
15 | Please help us maintain this project more efficiently! Before creating the issue make sure you shouldn't be creating it in one the below repos instead:
16 | - Core related: https://github.com/nextauthjs/next-auth
17 | - Docs related: https://github.com/nextauthjs/docs
18 |
19 | If you are in the correct repo, then proceed by providing the following information:
20 | - type: input
21 | id: title
22 | attributes:
23 | label: Title
24 | validations:
25 | required: true
26 | - type: textarea
27 | id: reproduction
28 | attributes:
29 | label: How to reproduce ☕️
30 | description: Please provide a link or code snippets to a minimal reproduction of the bug
31 | validations:
32 | required: true
33 | - type: markdown
34 | attributes:
35 | value: |
36 | We encourage you to use one of the templates set up on **CodeSandbox** to reproduce your issue:
37 | - [`next-auth-example`](https://codesandbox.io/s/next-auth-example-1kktb)
38 | - [`next-auth-typescript-example`](https://codesandbox.io/s/next-auth-typescript-example-se32w)
39 |
40 | 🚧 – _If you don't provide any way to reproduce the bug, the issue is at risk of being closed._
41 |
42 | - type: textarea
43 | id: description
44 | attributes:
45 | label: Your question/bug report 📓
46 | description: Please provide a more in-depth description of your request.
47 | validations:
48 | required: true
49 | - type: dropdown
50 | id: contributing
51 | attributes:
52 | label: Contributing 🙌🏽
53 | description: Are you willing to open a PR for this?
54 | multiple: false
55 | options:
56 | - "Yes, I am"
57 | - "No, I'm afraid I cannot help regarding this"
58 | validations:
59 | required: true
60 | - type: markdown
61 | attributes:
62 | value: |
63 | It takes a lot of work 🏋🏻♀️ maintaining a library like `next-auth`; any contribution is more than welcome 💚
64 |
65 |
66 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/pouchdb.yaml:
--------------------------------------------------------------------------------
1 | name: PouchDP
2 | description: File a support request for the PouchDB adapter
3 | labels: pouchdb
4 |
5 | # note: markdown sections will NOT appear as part of the issue as per documentation, rather they provide context to the user
6 | # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#markdown
7 |
8 |
9 | body:
10 | - type: markdown
11 | attributes:
12 | value: |
13 | Thanks for taking the time to fill out this issue!
14 | ### Important :exclamation:
15 | Please help us maintain this project more efficiently! Before creating the issue make sure you shouldn't be creating it in one the below repos instead:
16 | - Core related: https://github.com/nextauthjs/next-auth
17 | - Docs related: https://github.com/nextauthjs/docs
18 |
19 | If you are in the correct repo, then proceed by providing the following information:
20 | - type: input
21 | id: title
22 | attributes:
23 | label: Title
24 | validations:
25 | required: true
26 | - type: textarea
27 | id: reproduction
28 | attributes:
29 | label: How to reproduce ☕️
30 | description: Please provide a link or code snippets to a minimal reproduction of the bug
31 | validations:
32 | required: true
33 | - type: markdown
34 | attributes:
35 | value: |
36 | We encourage you to use one of the templates set up on **CodeSandbox** to reproduce your issue:
37 | - [`next-auth-example`](https://codesandbox.io/s/next-auth-example-1kktb)
38 | - [`next-auth-typescript-example`](https://codesandbox.io/s/next-auth-typescript-example-se32w)
39 |
40 | 🚧 – _If you don't provide any way to reproduce the bug, the issue is at risk of being closed._
41 |
42 | - type: textarea
43 | id: description
44 | attributes:
45 | label: Your question/bug report 📓
46 | description: Please provide a more in-depth description of your request.
47 | validations:
48 | required: true
49 | - type: dropdown
50 | id: contributing
51 | attributes:
52 | label: Contributing 🙌🏽
53 | description: Are you willing to open a PR for this?
54 | multiple: false
55 | options:
56 | - "Yes, I am"
57 | - "No, I'm afraid I cannot help regarding this"
58 | validations:
59 | required: true
60 | - type: markdown
61 | attributes:
62 | value: |
63 | It takes a lot of work 🏋🏻♀️ maintaining a library like `next-auth`; any contribution is more than welcome 💚
64 |
65 |
66 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/prisma.yaml:
--------------------------------------------------------------------------------
1 | name: Prisma
2 | description: File a support request for the Prisma adapter
3 | labels: prisma
4 |
5 | # note: markdown sections will NOT appear as part of the issue as per documentation, rather they provide context to the user
6 | # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#markdown
7 |
8 |
9 | body:
10 | - type: markdown
11 | attributes:
12 | value: |
13 | Thanks for taking the time to fill out this issue!
14 | ### Important :exclamation:
15 | Please help us maintain this project more efficiently! Before creating the issue make sure you shouldn't be creating it in one the below repos instead:
16 | - Core related: https://github.com/nextauthjs/next-auth
17 | - Docs related: https://github.com/nextauthjs/docs
18 |
19 | If you are in the correct repo, then proceed by providing the following information:
20 | - type: input
21 | id: title
22 | attributes:
23 | label: Title
24 | validations:
25 | required: true
26 | - type: textarea
27 | id: reproduction
28 | attributes:
29 | label: How to reproduce ☕️
30 | description: Please provide a link or code snippets to a minimal reproduction of the bug
31 | validations:
32 | required: true
33 | - type: markdown
34 | attributes:
35 | value: |
36 | We encourage you to use one of the templates set up on **CodeSandbox** to reproduce your issue:
37 | - [`next-auth-example`](https://codesandbox.io/s/next-auth-example-1kktb)
38 | - [`next-auth-typescript-example`](https://codesandbox.io/s/next-auth-typescript-example-se32w)
39 |
40 | 🚧 – _If you don't provide any way to reproduce the bug, the issue is at risk of being closed._
41 |
42 | - type: textarea
43 | id: description
44 | attributes:
45 | label: Your question/bug report 📓
46 | description: Please provide a more in-depth description of your request.
47 | validations:
48 | required: true
49 | - type: dropdown
50 | id: contributing
51 | attributes:
52 | label: Contributing 🙌🏽
53 | description: Are you willing to open a PR for this?
54 | multiple: false
55 | options:
56 | - "Yes, I am"
57 | - "No, I'm afraid I cannot help regarding this"
58 | validations:
59 | required: true
60 | - type: markdown
61 | attributes:
62 | value: |
63 | It takes a lot of work 🏋🏻♀️ maintaining a library like `next-auth`; any contribution is more than welcome 💚
64 |
65 |
66 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/typeorm-legacy.yaml:
--------------------------------------------------------------------------------
1 | name: TypeORM
2 | description: File a support request for the TypeORM adapter
3 | labels: typeorm
4 |
5 | # note: markdown sections will NOT appear as part of the issue as per documentation, rather they provide context to the user
6 | # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#markdown
7 |
8 |
9 | body:
10 | - type: markdown
11 | attributes:
12 | value: |
13 | Thanks for taking the time to fill out this issue!
14 | ### Important :exclamation:
15 | Please help us maintain this project more efficiently! Before creating the issue make sure you shouldn't be creating it in one the below repos instead:
16 | - Core related: https://github.com/nextauthjs/next-auth
17 | - Docs related: https://github.com/nextauthjs/docs
18 |
19 | If you are in the correct repo, then proceed by providing the following information:
20 | - type: input
21 | id: title
22 | attributes:
23 | label: Title
24 | validations:
25 | required: true
26 | - type: textarea
27 | id: reproduction
28 | attributes:
29 | label: How to reproduce ☕️
30 | description: Please provide a link or code snippets to a minimal reproduction of the bug
31 | validations:
32 | required: true
33 | - type: markdown
34 | attributes:
35 | value: |
36 | We encourage you to use one of the templates set up on **CodeSandbox** to reproduce your issue:
37 | - [`next-auth-example`](https://codesandbox.io/s/next-auth-example-1kktb)
38 | - [`next-auth-typescript-example`](https://codesandbox.io/s/next-auth-typescript-example-se32w)
39 |
40 | 🚧 – _If you don't provide any way to reproduce the bug, the issue is at risk of being closed._
41 |
42 | - type: textarea
43 | id: description
44 | attributes:
45 | label: Your question/bug report 📓
46 | description: Please provide a more in-depth description of your request.
47 | validations:
48 | required: true
49 | - type: dropdown
50 | id: contributing
51 | attributes:
52 | label: Contributing 🙌🏽
53 | description: Are you willing to open a PR for this?
54 | multiple: false
55 | options:
56 | - "Yes, I am"
57 | - "No, I'm afraid I cannot help regarding this"
58 | validations:
59 | required: true
60 | - type: markdown
61 | attributes:
62 | value: |
63 | It takes a lot of work 🏋🏻♀️ maintaining a library like `next-auth`; any contribution is more than welcome 💚
64 |
65 |
66 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/upstash-redis.yaml:
--------------------------------------------------------------------------------
1 | name: Upstash Redis
2 | description: File a support request for the Upstash Redis adapter
3 | labels: upstash-redis
4 |
5 | # note: markdown sections will NOT appear as part of the issue as per documentation, rather they provide context to the user
6 | # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#markdown
7 |
8 | body:
9 | - type: markdown
10 | attributes:
11 | value: |
12 | Thanks for taking the time to fill out this issue!
13 | ### Important :exclamation:
14 | Please help us maintain this project more efficiently! Before creating the issue make sure you shouldn't be creating it in one the below repos instead:
15 | - Core related: https://github.com/nextauthjs/next-auth
16 | - Docs related: https://github.com/nextauthjs/docs
17 |
18 | If you are in the correct repo, then proceed by providing the following information:
19 | - type: input
20 | id: title
21 | attributes:
22 | label: Title
23 | validations:
24 | required: true
25 | - type: textarea
26 | id: reproduction
27 | attributes:
28 | label: How to reproduce ☕️
29 | description: Please provide a link or code snippets to a minimal reproduction of the bug
30 | validations:
31 | required: true
32 | - type: markdown
33 | attributes:
34 | value: |
35 | We encourage you to use one of the templates set up on **CodeSandbox** to reproduce your issue:
36 | - [`next-auth-example`](https://codesandbox.io/s/next-auth-example-1kktb)
37 | - [`next-auth-typescript-example`](https://codesandbox.io/s/next-auth-typescript-example-se32w)
38 |
39 | 🚧 – _If you don't provide any way to reproduce the bug, the issue is at risk of being closed._
40 |
41 | - type: textarea
42 | id: description
43 | attributes:
44 | label: Your question/bug report 📓
45 | description: Please provide a more in-depth description of your request.
46 | validations:
47 | required: true
48 | - type: dropdown
49 | id: contributing
50 | attributes:
51 | label: Contributing 🙌🏽
52 | description: Are you willing to open a PR for this?
53 | multiple: false
54 | options:
55 | - "Yes, I am"
56 | - "No, I'm afraid I cannot help regarding this"
57 | validations:
58 | required: true
59 | - type: markdown
60 | attributes:
61 | value: |
62 | It takes a lot of work 🏋🏻♀️ maintaining a library like `next-auth`; any contribution is more than welcome 💚
63 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
16 |
17 | ## Reasoning 💡
18 |
19 |
25 |
26 | ## Checklist 🧢
27 |
28 |
31 |
32 | - [ ] Documentation
33 | - [ ] Tests
34 | - [ ] Ready to be merged
35 |
36 |
37 |
38 | ## Affected issues 🎟
39 |
40 |
52 |
--------------------------------------------------------------------------------
/.github/labeler.yml:
--------------------------------------------------------------------------------
1 | fauna:
2 | - packages/fauna/**/*
3 |
4 | dynamodb:
5 | - packages/dynamodb/**/*
6 |
7 | prisma:
8 | - packages/prisma/**/*
9 |
10 | mongodb:
11 | - packages/mongodb/**/*
12 |
13 | neo4j:
14 | - packages/neo4j/**/*
15 |
16 | typeorm:
17 | - packages/typeorm-legacy/**/*
18 |
19 | firebase:
20 | - packages/firebase/**/*
21 |
22 | pouchdb:
23 | - packages/pouchdb/**/*
24 |
25 | sequelize:
26 | - packages/sequelize/**/*
27 |
28 | dgraph:
29 | - packages/dgraph/**/*
30 |
31 | upstash-redis:
32 | - packages/upstash-redis/**/*
33 |
34 | documentation:
35 | - ./**/*.md
36 |
37 | tests:
38 | - jest.config.js
39 | - packages/**/tests/*
40 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Number of days of inactivity before an issue becomes stale
2 | daysUntilStale: 90
3 | # Number of days of inactivity before a stale issue is closed
4 | daysUntilClose: 14
5 | # Issues with these labels will never be considered stale
6 | exemptLabels:
7 | - pinned
8 | - security
9 | - priority
10 | - bug
11 | # Label to use when marking an issue as stale
12 | staleLabel: stale
13 | # Comment to post when marking an issue as stale. Set to `false` to disable
14 | markComment: >
15 | Hi there! It looks like this issue hasn't had any activity for a while.
16 | It will be closed if no further activity occurs. If you think your issue
17 | is still relevant, feel free to comment on it to keep it open.
18 | Thanks!
19 | # Comment to post when closing a stale issue. Set to `false` to disable
20 | closeComment: >
21 | Hi there! It looks like this issue hasn't had any activity for a while.
22 | To keep things tidy, I am going to close this issue for now.
23 | If you think your issue is still relevant, just leave a comment
24 | and I will reopen it.
25 | Thanks!
26 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ canary, main ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ canary ]
20 | schedule:
21 | - cron: '19 2 * * 4'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 |
28 | strategy:
29 | fail-fast: false
30 | matrix:
31 | language: [ 'javascript' ]
32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
33 | # Learn more:
34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
35 |
36 | steps:
37 | - name: Checkout repository
38 | uses: actions/checkout@v2
39 |
40 | # Initializes the CodeQL tools for scanning.
41 | - name: Initialize CodeQL
42 | uses: github/codeql-action/init@v1
43 | with:
44 | languages: ${{ matrix.language }}
45 | # If you wish to specify custom queries, you can do so here or in a config file.
46 | # By default, queries listed here will override any specified in a config file.
47 | # Prefix the list here with "+" to use these queries and those in the config file.
48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
49 |
50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
51 | # If this step fails, then you should remove it and run the build manually (see below)
52 | - name: Autobuild
53 | uses: github/codeql-action/autobuild@v1
54 |
55 | # ℹ️ Command-line programs to run using the OS shell.
56 | # 📚 https://git.io/JvXDl
57 |
58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
59 | # and modify them (or add more) to build your code if your project
60 | # uses a compiled language
61 |
62 | #- run: |
63 | # make bootstrap
64 | # make release
65 |
66 | - name: Perform CodeQL Analysis
67 | uses: github/codeql-action/analyze@v1
68 |
--------------------------------------------------------------------------------
/.github/workflows/labeler.yml:
--------------------------------------------------------------------------------
1 | name: "Pull Request Labeler"
2 | on:
3 | - pull_request_target
4 |
5 | jobs:
6 | triage:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/labeler@main
10 | with:
11 | repo-token: "${{ secrets.GITHUB_TOKEN }}"
12 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | - next
8 | pull_request:
9 | branches:
10 | - main
11 | - next
12 |
13 | jobs:
14 | publish:
15 | name: "Test, Build, Publish"
16 | runs-on: ubuntu-latest
17 | env:
18 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
20 | UPSTASH_REDIS_KEY: ${{ secrets.UPSTASH_REDIS_KEY }}
21 | UPSTASH_REDIS_URL: ${{ secrets.UPSTASH_REDIS_URL }}
22 | steps:
23 | - uses: actions/checkout@v2
24 | with:
25 | fetch-depth: 0
26 | persist-credentials: false
27 | token: ${{ secrets.GH_PAT }}
28 | - uses: actions/setup-node@v2
29 | with:
30 | node-version: "16"
31 | - uses: bahmutov/npm-install@v1
32 | - name: Test (changed packages)
33 | run: lerna run test --concurrency 3 --since HEAD~
34 | - name: Build (changed packages)
35 | run: lerna run build --concurrency 3 --since
36 | - name: Authenticate with NPM
37 | run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> .npmrc
38 | - name: Configure CI Git User
39 | run: |
40 | git config --global user.email nextauth@gmail.com
41 | git config --global user.name "NextAuth.js"
42 | git config remote.origin.url https://x-access-token:${{ secrets.GH_PAT }}@github.com/$GITHUB_REPOSITORY
43 | - name: Publish to @next
44 | if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/next' }}
45 | run: |
46 | lerna publish --canary --preid next \
47 | --dist-tag next --conventional-prerelease \
48 | --create-release github --yes \
49 | -m "chore(release): create release [skip ci]"
50 | - name: Publish to @experimental
51 | if: ${{ github.base_ref == 'main' || github.base_ref == 'next' }}
52 | run: |
53 | lerna publish --preid pr.${{ github.event.number }}-${GITHUB_SHA::8} \
54 | --no-changelog --no-push --canary --dist-tag experimental --yes
55 | - name: Publish to @latest
56 | if: ${{github.event_name == 'push' && github.ref == 'refs/heads/main'}}
57 | run: |
58 | lerna publish --create-release github --yes \
59 | -m "chore(release): create release [skip ci]"
60 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | lerna-debug.log
3 | dist
4 | dev.db
5 | .eslintcache
6 | .devcontainer
7 | coverage
8 | dev.db-journal
9 | packages/prisma/prisma/migrations
10 | packages/fauna/fauna/migrations
11 | dynamodblocal-bin
--------------------------------------------------------------------------------
/.husky/.gitignore:
--------------------------------------------------------------------------------
1 | _
2 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx lint-staged
5 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 16
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | - Using welcoming and inclusive language
18 | - Being respectful of differing viewpoints and experiences
19 | - Gracefully accepting constructive criticism
20 | - Focusing on what is best for the community
21 | - Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | - The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | - Trolling, insulting/derogatory comments, and personal or political attacks
28 | - Public or private harassment
29 | - Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | - Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting me@iaincollins.com. All complaints will be reviewed and
59 | investigated and will result in a response that is deemed necessary and
60 | appropriate to the circumstances. The project team is obligated to maintain
61 | confidentiality with regard to the reporter of an incident. Further details of
62 | specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing guide
2 |
3 | Contributions and feedback on your experience of using this software are welcome.
4 |
5 | This includes bug reports, feature requests, ideas, pull requests, and examples of how you have used this software.
6 |
7 | Please see the [Code of Conduct](CODE_OF_CONDUCT.md) and follow any templates configured in GitHub when reporting bugs, requesting enhancements, or contributing code.
8 |
9 | Please raise any significant new functionality or breaking change an issue for discussion before raising a Pull Request for it.
10 |
11 | ## For contributors
12 |
13 | Anyone can be a contributor. Either you found a typo, or you have an awesome feature request you could implement, we encourage you to create a Pull Request.
14 |
15 | ### Pull Requests
16 |
17 | - The latest changes are always in `main`, so please make your Pull Request against that branch.
18 | - Pull Requests should be raised for any change
19 |
20 | ### Setting up local environment
21 |
22 | The local environment consists of two pieces:
23 |
24 | 1. The top-level package.json and its dependencies, like `lerna`.
25 | 2. The package-level dependencies which can be installed via npm. Any other package specific instructions can be found in their README's or the [docs](https://next-auth.js.org/adapters/overview).
26 |
27 | #### Testing
28 |
29 | Testing takes place on a per-adapter basis. Each adapter in the `packages` subdirectory should have an npm test script which will setup a test environment, often consiting of a docker container of the appropriate databse, and a test-runner like jest.
30 |
31 | ## For maintainers
32 |
33 | ### Recommended Scopes
34 |
35 | A typical conventional commit looks like this:
36 |
37 | ```
38 | type(scope): title
39 |
40 | body
41 | ```
42 |
43 | Scope is the part that will help groupping the different commit types in the release notes.
44 |
45 | Some recommened scopes are:
46 |
47 | - **adapter** - Adapter related changes. (eg.: "feat(prisma): add prisma adapter", "docs(prisma): fix typo in X documentation"
48 |
49 | > NOTE: If you are not sure which scope to use, you can simply ignore it. (eg.: "feat: add something"). Adding the correct type already helps a lot when analyzing the commit messages.
50 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ISC License
2 |
3 | Copyright (c) 2018-2021, Iain Collins
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any
6 | purpose with or without fee is hereby granted, provided that the above
7 | copyright notice and this permission notice appear in all copies.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: "ts-jest",
3 | testEnvironment: "node",
4 | modulePathIgnorePatterns: ["dist/", "node_modules/"],
5 | // TODO: Set-up with Codecov https://about.codecov.io/
6 | // collectCoverage: true,
7 | // coverageReporters: ["json", "html"],
8 | }
9 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "lerna": "2.11.0",
3 | "packages": ["packages/*"],
4 | "version": "independent",
5 | "npmClient": "yarn",
6 | "useWorkspaces": true,
7 | "command": {
8 | "publish": {
9 | "conventionalCommits": true,
10 | "verifyAccess": false
11 | }
12 | },
13 | "ignoreChanges": ["**/tests/**", "**/CHANGELOG.md"],
14 | "publishConfig": {
15 | "access": "public"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "adapters",
3 | "version": "0.0.0",
4 | "repository": "https://github.com/nextauthjs/adapters.git",
5 | "author": "William Luke ",
6 | "contributors": [
7 | "Balázs Orbán ",
8 | "Nico Domino "
9 | ],
10 | "license": "ISC",
11 | "private": true,
12 | "scripts": {
13 | "build": "lerna run build",
14 | "canary": "lerna publish --canary",
15 | "prepare": "husky install",
16 | "lint": "eslint .",
17 | "lint:fix": "eslint . --fix && prettier --write"
18 | },
19 | "workspaces": [
20 | "packages/*"
21 | ],
22 | "devDependencies": {
23 | "@babel/cli": "^7.14.3",
24 | "@babel/plugin-transform-runtime": "^7.14.3",
25 | "@babel/preset-env": "^7.14.2",
26 | "@types/jest": "^26.0.23",
27 | "@types/nodemailer": "^6.4.4",
28 | "@typescript-eslint/eslint-plugin": "^4.24.0",
29 | "@typescript-eslint/parser": "^4.24.0",
30 | "eslint": "^7.27.0",
31 | "eslint-config-prettier": "^8.3.0",
32 | "eslint-config-standard-with-typescript": "^20.0.0",
33 | "eslint-plugin-import": "^2.23.3",
34 | "eslint-plugin-node": "^11.1.0",
35 | "eslint-plugin-promise": "^5.1.0",
36 | "husky": ">=6",
37 | "jest": "^27.0.3",
38 | "lerna": "^4.0.0",
39 | "lint-staged": ">=10",
40 | "next-auth": "^4.0.1",
41 | "prettier": "^2.3.0",
42 | "ts-jest": "^27.0.3",
43 | "typescript": "^4.2.4"
44 | },
45 | "prettier": {
46 | "semi": false
47 | },
48 | "eslintConfig": {
49 | "parser": "@typescript-eslint/parser",
50 | "parserOptions": {
51 | "project": "./tsconfig.json"
52 | },
53 | "rules": {
54 | "@typescript-eslint/explicit-function-return-type": "off",
55 | "@typescript-eslint/strict-boolean-expressions": "off",
56 | "@typescript-eslint/naming-convention": "off",
57 | "@typescript-eslint/consistent-type-imports": "warn"
58 | },
59 | "extends": [
60 | "standard-with-typescript",
61 | "prettier"
62 | ],
63 | "ignorePatterns": [
64 | "node_modules",
65 | "test",
66 | "next-env.d.ts",
67 | "types",
68 | "www",
69 | ".next",
70 | "dist"
71 | ],
72 | "globals": {
73 | "localStorage": "readonly",
74 | "location": "readonly",
75 | "fetch": "readonly"
76 | }
77 | },
78 | "lint-staged": {
79 | "*.{js,ts}": [
80 | "eslint --cache --fix",
81 | "prettier --write"
82 | ],
83 | "*.{css,md,json}": "prettier --write"
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/packages/dgraph/.gitignore:
--------------------------------------------------------------------------------
1 | test.schema.gql
--------------------------------------------------------------------------------
/packages/dgraph/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [1.0.2](https://github.com/nextauthjs/adapters/compare/@next-auth/dgraph-adapter@1.0.1...@next-auth/dgraph-adapter@1.0.2) (2021-12-06)
7 |
8 | **Note:** Version bump only for package @next-auth/dgraph-adapter
9 |
--------------------------------------------------------------------------------
/packages/dgraph/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("../../jest.config")
2 |
--------------------------------------------------------------------------------
/packages/dgraph/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@next-auth/dgraph-adapter",
3 | "version": "1.0.2",
4 | "description": "Dgraph adapter for next-auth.",
5 | "homepage": "https://next-auth.js.org",
6 | "repository": "https://github.com/nextauthjs/adapters",
7 | "bugs": {
8 | "url": "https://github.com/nextauthjs/adapters/issues"
9 | },
10 | "author": "Arnaud Derbey ",
11 | "contributors": [],
12 | "main": "dist/index.js",
13 | "files": [
14 | "dist",
15 | "index.d.ts"
16 | ],
17 | "license": "ISC",
18 | "keywords": [
19 | "next-auth",
20 | "next.js",
21 | "dgraph",
22 | "graphql"
23 | ],
24 | "private": false,
25 | "publishConfig": {
26 | "access": "public"
27 | },
28 | "scripts": {
29 | "build": "tsc",
30 | "test": "./tests/test.sh"
31 | },
32 | "peerDependencies": {
33 | "jsonwebtoken": "^8.5.1",
34 | "next-auth": "^4.0.1"
35 | },
36 | "devDependencies": {
37 | "@types/jest": "^26.0.24",
38 | "@types/jsonwebtoken": "^8.5.5",
39 | "@types/node-fetch": "^2.5.11",
40 | "jest": "^27.0.6",
41 | "ts-jest": "^27.0.3"
42 | },
43 | "dependencies": {
44 | "jsonwebtoken": "^8.5.1",
45 | "node-fetch": "^2.6.1"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/packages/dgraph/src/client.ts:
--------------------------------------------------------------------------------
1 | import * as jwt from "jsonwebtoken"
2 | import fetch from "node-fetch"
3 |
4 | import type { HeadersInit } from "node-fetch"
5 |
6 | export interface DgraphClientParams {
7 | endpoint: string
8 | /**
9 | * `X-Auth-Token` header value
10 | *
11 | * [Dgraph Cloud Authentication](https://dgraph.io/docs/cloud/cloud-api/overview/#dgraph-cloud-authentication)
12 | */
13 | authToken: string
14 | /** [Using JWT and authorization claims](https://dgraph.io/docs/graphql/authorization/authorization-overview#using-jwts-and-authorization-claims) */
15 | jwtSecret?: string
16 | /**
17 | * @default "RS256"
18 | *
19 | * [Using JWT and authorization claims](https://dgraph.io/docs/graphql/authorization/authorization-overview#using-jwts-and-authorization-claims)
20 | */
21 | jwtAlgorithm?: "HS256" | "RS256"
22 | /**
23 | * @default "Authorization"
24 | *
25 | * [Using JWT and authorization claims](https://dgraph.io/docs/graphql/authorization/authorization-overview#using-jwts-and-authorization-claims)
26 | */
27 | authHeader?: string
28 | }
29 |
30 | export class DgraphClientError extends Error {
31 | name = "DgraphClientError"
32 | constructor(errors: any[], query: string, variables: any) {
33 | super(errors.map((error) => error.message).join("\n"))
34 | console.error({ query, variables })
35 | }
36 | }
37 |
38 | export function client(params: DgraphClientParams) {
39 | if (!params.authToken) {
40 | throw new Error("Dgraph client error: Please provide an api key")
41 | }
42 | if (!params.endpoint) {
43 | throw new Error("Dgraph client error: Please provide a graphql endpoint")
44 | }
45 |
46 | const {
47 | endpoint,
48 | authToken,
49 | jwtSecret,
50 | jwtAlgorithm = "HS256",
51 | authHeader = "Authorization",
52 | } = params
53 | const headers: HeadersInit = {
54 | "Content-Type": "application/json",
55 | "X-Auth-Token": authToken,
56 | }
57 |
58 | if (authHeader && jwtSecret) {
59 | headers[authHeader] = jwt.sign({ nextAuth: true }, jwtSecret, {
60 | algorithm: jwtAlgorithm,
61 | })
62 | }
63 |
64 | return {
65 | async run(
66 | query: string,
67 | variables?: Record
68 | ): Promise {
69 | const response = await fetch(endpoint, {
70 | method: "POST",
71 | headers,
72 | body: JSON.stringify({ query, variables }),
73 | })
74 |
75 | const { data = {}, errors } = await response.json()
76 | if (errors?.length) {
77 | throw new DgraphClientError(errors, query, variables)
78 | }
79 | return Object.values(data)[0] as any
80 | },
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/packages/dgraph/src/graphql/fragments.ts:
--------------------------------------------------------------------------------
1 | export const User = /* GraphQL */ `
2 | fragment UserFragment on User {
3 | email
4 | id
5 | image
6 | name
7 | emailVerified
8 | }
9 | `
10 |
11 | export const Account = /* GraphQL */ `
12 | fragment AccountFragment on Account {
13 | id
14 | type
15 | provider
16 | providerAccountId
17 | expires_at
18 | token_type
19 | scope
20 | access_token
21 | refresh_token
22 | id_token
23 | session_state
24 | }
25 | `
26 | export const Session = /* GraphQL */ `
27 | fragment SessionFragment on Session {
28 | expires
29 | id
30 | sessionToken
31 | }
32 | `
33 |
34 | export const VerificationToken = /* GraphQL */ `
35 | fragment VerificationTokenFragment on VerificationToken {
36 | identifier
37 | token
38 | expires
39 | }
40 | `
41 |
--------------------------------------------------------------------------------
/packages/dgraph/src/graphql/schema.gql:
--------------------------------------------------------------------------------
1 | type Account
2 | @auth(
3 | delete: { rule: "{$nextAuth: { eq: true } }" }
4 | add: { rule: "{$nextAuth: { eq: true } }" }
5 | query: { rule: "{$nextAuth: { eq: true } }" }
6 | update: { rule: "{$nextAuth: { eq: true } }" }
7 | ) {
8 | id: ID
9 | type: String
10 | provider: String @search(by: [hash])
11 | providerAccountId: String @search(by: [hash])
12 | refreshToken: String
13 | expires_at: Int64
14 | accessToken: String
15 | token_type: String
16 | refresh_token: String
17 | access_token: String
18 | scope: String
19 | id_token: String
20 | session_state: String
21 | user: User @hasInverse(field: "accounts")
22 | }
23 | type Session
24 | @auth(
25 | delete: { rule: "{$nextAuth: { eq: true } }" }
26 | add: { rule: "{$nextAuth: { eq: true } }" }
27 | query: { rule: "{$nextAuth: { eq: true } }" }
28 | update: { rule: "{$nextAuth: { eq: true } }" }
29 | ) {
30 | id: ID
31 | expires: DateTime
32 | sessionToken: String @search(by: [hash])
33 | user: User @hasInverse(field: "sessions")
34 | }
35 | type User
36 | @auth(
37 | query: {
38 | or: [
39 | {
40 | rule: """
41 | query ($userId: String!) {queryUser(filter: { id: { eq: $userId } } ) {id}}
42 | """
43 | }
44 | { rule: "{$nextAuth: { eq: true } }" }
45 | ]
46 | }
47 | delete: { rule: "{$nextAuth: { eq: true } }" }
48 | add: { rule: "{$nextAuth: { eq: true } }" }
49 | update: {
50 | or: [
51 | {
52 | rule: """
53 | query ($userId: String!) {queryUser(filter: { id: { eq: $userId } } ) {id}}
54 | """
55 | }
56 | { rule: "{$nextAuth: { eq: true } }" }
57 | ]
58 | }
59 | ) {
60 | id: ID
61 | name: String
62 | email: String @search(by: [hash])
63 | emailVerified: DateTime
64 | image: String
65 | accounts: [Account] @hasInverse(field: "user")
66 | sessions: [Session] @hasInverse(field: "user")
67 | }
68 |
69 | type VerificationToken
70 | @auth(
71 | delete: { rule: "{$nextAuth: { eq: true } }" }
72 | add: { rule: "{$nextAuth: { eq: true } }" }
73 | query: { rule: "{$nextAuth: { eq: true } }" }
74 | update: { rule: "{$nextAuth: { eq: true } }" }
75 | ) {
76 | id: ID
77 | identifier: String @search(by: [hash])
78 | token: String @search(by: [hash])
79 | expires: DateTime
80 | }
81 |
82 | # Dgraph.Authorization {"VerificationKey":"","Header":"","Namespace":"","Algo":"RS256"}
83 |
--------------------------------------------------------------------------------
/packages/dgraph/src/utils.ts:
--------------------------------------------------------------------------------
1 | // https://github.com/honeinc/is-iso-date/blob/master/index.js
2 | const isoDateRE =
3 | /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/
4 |
5 | function isDate(value: any) {
6 | return value && isoDateRE.test(value) && !isNaN(Date.parse(value))
7 | }
8 |
9 | export const format = {
10 | from(object?: Record): T | null {
11 | const newObject: Record = {}
12 | if (!object) return null
13 | for (const key in object) {
14 | const value = object[key]
15 | if (isDate(value)) {
16 | newObject[key] = new Date(value)
17 | } else {
18 | newObject[key] = value
19 | }
20 | }
21 |
22 | return newObject as T
23 | },
24 | }
25 |
--------------------------------------------------------------------------------
/packages/dgraph/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | import { DgraphAdapter, format } from "../src"
2 | import { client as dgraphClient } from "../src/client"
3 | import * as fragments from "../src/graphql/fragments"
4 | import { runBasicTests } from "../../../basic-tests"
5 | import fs from "fs"
6 | import path from "path"
7 |
8 | import type { DgraphClientParams } from "../src"
9 |
10 | const params: DgraphClientParams = {
11 | endpoint: "http://localhost:8080/graphql",
12 | authToken: "test",
13 | jwtAlgorithm: "RS256",
14 | jwtSecret: fs.readFileSync(path.join(process.cwd(), "/tests/private.key"), {
15 | encoding: "utf8",
16 | }),
17 | }
18 |
19 | /** TODO: Add test to `dgraphClient` */
20 | const c = dgraphClient(params)
21 |
22 | runBasicTests({
23 | adapter: DgraphAdapter(params),
24 | db: {
25 | id: () => "0x0a0a00a00",
26 | async disconnect() {
27 | await c.run(/* GraphQL */ `
28 | mutation {
29 | deleteUser(filter: {}) {
30 | numUids
31 | }
32 | deleteVerificationToken(filter: {}) {
33 | numUids
34 | }
35 | deleteSession(filter: {}) {
36 | numUids
37 | }
38 | deleteAccount(filter: {}) {
39 | numUids
40 | }
41 | }
42 | `)
43 | },
44 | async user(id) {
45 | const result = await c.run(
46 | /* GraphQL */ `
47 | query ($id: ID!) {
48 | getUser(id: $id) {
49 | ...UserFragment
50 | }
51 | }
52 | ${fragments.User}
53 | `,
54 | { id }
55 | )
56 |
57 | return format.from(result)
58 | },
59 | async session(sessionToken) {
60 | const result = await c.run(
61 | /* GraphQL */ `
62 | query ($sessionToken: String!) {
63 | querySession(filter: { sessionToken: { eq: $sessionToken } }) {
64 | ...SessionFragment
65 | user {
66 | id
67 | }
68 | }
69 | }
70 | ${fragments.Session}
71 | `,
72 | { sessionToken }
73 | )
74 |
75 | const { user, ...session } = result?.[0] ?? {}
76 | if (!user?.id) return null
77 | return format.from({ ...session, userId: user.id })
78 | },
79 | async account(provider_providerAccountId) {
80 | const result = await c.run(
81 | /* GraphQL */ `
82 | query ($providerAccountId: String = "", $provider: String = "") {
83 | queryAccount(
84 | filter: {
85 | providerAccountId: { eq: $providerAccountId }
86 | provider: { eq: $provider }
87 | }
88 | ) {
89 | ...AccountFragment
90 | user {
91 | id
92 | }
93 | }
94 | }
95 | ${fragments.Account}
96 | `,
97 | provider_providerAccountId
98 | )
99 |
100 | const account = format.from(result?.[0])
101 | if (!account?.user) return null
102 |
103 | account.userId = account.user.id
104 | delete account.user
105 | return account
106 | },
107 | async verificationToken(identifier_token) {
108 | const result = await c.run(
109 | /* GraphQL */ `
110 | query ($identifier: String = "", $token: String = "") {
111 | queryVerificationToken(
112 | filter: { identifier: { eq: $identifier }, token: { eq: $token } }
113 | ) {
114 | ...VerificationTokenFragment
115 | }
116 | }
117 | ${fragments.VerificationToken}
118 | `,
119 | identifier_token
120 | )
121 |
122 | return format.from(result?.[0])
123 | },
124 | },
125 | })
126 |
--------------------------------------------------------------------------------
/packages/dgraph/tests/private.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIJKQIBAAKCAgEAxqyvd82VacXMBLUADZt+euSNUNJ276XgvH4HW4ms5iQZDgYI
3 | PKxyaZ+wk8EMYSB1dymJ3WQpm0JKHqgTW+z/edfYFQXkduHN/zoIpxMAMyZGsTBi
4 | dGo0xJSHTCDCdYCCBlG9R1ljjhf0l9ChBP7W7lSXaRU/XS/tMH1qYMpsUwDav4G/
5 | RDI3A4t29JRGqU4mnFa5o3XBCxU4ANCp1JaQevzAYox8EGPZ1YZGmhRgca51dBee
6 | d9QKqWjfXP4wboC1ppglm+kPgFUaCiXB8KyfIixhlvzZiO4RLvZw+cILt586vXGz
7 | Ny49eVUTiIOoTZuG/79pCeBS8BCbB4l6y274y42hUN83gHxQ32Y++DI40jz5iGN8
8 | 5Dj6yDDjKwvwqVhCx/kVJFrmyrTJz/E0cp38FeIi7D6e0eXj7G97K+wkNdc4oTs1
9 | DsDPzhO/7wxQOZIjvNp+DJAfxin5MbM+UKoopvJj3sUMHVrTteWxZg94mmLjg2Kn
10 | JYBuSn8kiFPYQ0F5MjE7df4tDDTGJ/VEFIG5EkQffaNYhW0Z5ORLvW1R1Yd1/ew3
11 | UWo+mZ7XAUGLF6clsWSQvzSrrNMYzCk5Fa0LwvMtQdEVLL3q7/KsEHD7N78EVlmE
12 | DlOtC21UidUqXnawCE1QIjAHqFsNNPR2j0lgOoEjrGdzrvUg6hNV9m6CbSECAwEA
13 | AQKCAgAjr8kk/+yiv0DSZ6DG0PN7J6qqpeNvUKB5uzmfG6/O9xT5C+RW4bL7fg+9
14 | uqN6ntX6vZ9iASfoF5QwxYgUrxGE1VyfChvrrsvN2KLNQAB9L5brJQHKX3lzBir3
15 | ZbsIWDkC4ZPaSRg04eCxlGwX9Z6t2MwJuCNVndJBL4X4NOQYVML2O1wb59kx7c9E
16 | R44Zw0v0MS/PSMuQLhONMe4Pnav+K4BzM0DlwMnULPZpntdkFC5M2CFC7PetToUw
17 | swgIEV6PuiynQMnkB2VSBU486QT8onQ1Jt38VqcHhITumAh6x0NJ3C6Q7uFj9gA4
18 | OU32AsXREpTPjVfYf2MZi3xfJmPR+1JTqmnhWY7g/v3K5MpFO9HGmcETNpV4YXRv
19 | U18Bx+m5FsKp0tFASyS/6PJoDAJ/a6yQxVNc1nYL8AKTFqod/0pQz2w2yFGR2t1g
20 | Ui+7HQrWRpdvp2vDJK2GJLs+thybtd73QwsKJ2LFHS91eQ1y1BsSI4z1Ph8/66xK
21 | uQVWfeQqQIhbM8m/pzOYNw90jRx9raKZ6QpdmLqoKj4WF3a/KvLc0TO678wzVoSM
22 | qBDH9FwmkebNHWEMR8rR5Fb1ZVHclSde6DqdPBTvcQzMk66ZGMHB746G68620iKs
23 | YJ6dFDBt3XBnhhOjPhCCH4XR8ZIGTgwxC9hry17/sUMEU5iS8QKCAQEA7WnbfI+h
24 | oLnfw0M6uxIrvl1MMip1Zq/f2/q3HIpE6qLuPoy4fzjONNYm8QBwdJSVPviMCsFx
25 | rU2IIHLeQGUSvMIIcWzn+EWKl3XTzirdn9uYZPPqGr/YuoLW/uN2TCppBbzT1jtA
26 | bbQYUfvyF+ysU+F9amLSdDsqM3MwaFMNChcf3XLMz7QFgoWIDSejq4Uhy6y22KEi
27 | qg+VprX9OejzUQLb0I8ko9S3dKAHkhUZJ8kxowu5oqaaGpowBhko84zKpNrGbinG
28 | bA0+LTxAUKaHhioWWgXya976DQRBdTkp7wOWuD/jnL3wnIHDYF0TKYuidu98d+zH
29 | b/+EH/wPEK4DrwKCAQEA1jpwJm2CDkw41TNexLectOlAjVw9xMt+10hLZ2PYOuwd
30 | kThLYU9zqYIp9thj9/Ddqkx286qHaX92W2q0SZmhuXeNLmcG71QGJp/6uC+up0Hk
31 | 7aFPoQ3uS7JQN5YwinUy/0vbTsxmko0Ie9y2gA0bWDV4Yu5zr/vYd/bLD55GPRD/
32 | WWGWkDlzlQqedQkjaCSRskm6nyFdTSsruw6RMdNiZK6jBR2aY0SsFmJmOwrTrPCS
33 | llg+zaUtqwgC4tLROx8R5rkJh8S+/KjRN46oXPphQLTJlNZu1uTjV5Ue/BqpHgor
34 | hJLgZwfA7YXJFfiSfjYFYTj9vm9Wx50zJSKiEZxALwKCAQEA6Czcy8y/GKqN7Kwj
35 | lGypwMoGyQyCsYCPoNZoGo4R5ZCfAyalCy2nYz6G6KswTqI77lAszBvvqramyGzt
36 | cvYlQ9lRXnNNy5tedM5y6y06fanIN/ndWHmDXqqzzKLvvn6/JDBMzjY1xNMZ8Zs9
37 | Xy5CPOnIt7Ca9bYiiBw/G9cUamjA7dTl/L2locYqjgrU4dkZetCWI/Y5KyyAgn95
38 | fBeXVANCqoxCHcHaA0C5BqCBcEous6+0xB6/mAJvspcKWFu4lU2qPnO2K1csFhrV
39 | HsoswQUJxNIKCHoP+YjO5u+XVbohvGAmnNOXqcaxJdz/72Ix6LQ9+h3h0GKGeK0M
40 | opg62wKCAQEAnyRoXdOp8s8ixRbVRtOTwT0prBmi9UeqoWjeQx8D6bmvuUqVjOOF
41 | 6517aRmVIgI32SPWlerPj0qV9RFOfwJ3Bp1OLvNwTmgf7Z+YlC0v1KZ51yGnUuBT
42 | br43IyQaSTEJQmfqsh3b8PB+Je1vUa7q6ltGZE/5dvli9LNMY/zS9thiqNZ7EAbt
43 | 2wE5d33jZKEN7uEglsglVIdGhD4tFFOQ23R0O/+iyi2gnTxZ73B6kRVh//fsJ76W
44 | L2DTLAcqUX4iQUCiWM6Kho0uZtQ+NFv31Sa4PS4SxubgEBcCHov7qAosC99EfqVe
45 | 59Qj7oNq6AFfe7rnnQl+8OjRrruMpAJsFwKCAQBxq1apDQTav7QW9Sfe19POZas0
46 | b0XIETL3mEh25uCqPTmoaKo45opgw0Cn7zpuy/NntKlG/cnPYneQh91bViqid/Iv
47 | 3M88vQJmS2e4abozqa7iNjd/XwmBcCgdR2yx51oJ9q9dfd2ejKfMDzm0uHs5U7ay
48 | pOlUch5OT0s5utZC4FbeziZ8Th61DtmIHOxQpNYpPXogdkbGSaOhL6dezPOAwJnJ
49 | B2zjH7N1c+dz+5HheVbN3M08aN9DdyD1xsmd8eZVTAi1wcp51GY6cb7G0gE2SzOp
50 | UNtVbc17n82jJ5Qr4ggSRU1QWNBZT9KX4U2/nTe3U5C3+ni4p+opI9Q3vSYw
51 | -----END RSA PRIVATE KEY-----
--------------------------------------------------------------------------------
/packages/dgraph/tests/public.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PUBLIC KEY-----
2 | MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxqyvd82VacXMBLUADZt+
3 | euSNUNJ276XgvH4HW4ms5iQZDgYIPKxyaZ+wk8EMYSB1dymJ3WQpm0JKHqgTW+z/
4 | edfYFQXkduHN/zoIpxMAMyZGsTBidGo0xJSHTCDCdYCCBlG9R1ljjhf0l9ChBP7W
5 | 7lSXaRU/XS/tMH1qYMpsUwDav4G/RDI3A4t29JRGqU4mnFa5o3XBCxU4ANCp1JaQ
6 | evzAYox8EGPZ1YZGmhRgca51dBeed9QKqWjfXP4wboC1ppglm+kPgFUaCiXB8Kyf
7 | IixhlvzZiO4RLvZw+cILt586vXGzNy49eVUTiIOoTZuG/79pCeBS8BCbB4l6y274
8 | y42hUN83gHxQ32Y++DI40jz5iGN85Dj6yDDjKwvwqVhCx/kVJFrmyrTJz/E0cp38
9 | FeIi7D6e0eXj7G97K+wkNdc4oTs1DsDPzhO/7wxQOZIjvNp+DJAfxin5MbM+UKoo
10 | pvJj3sUMHVrTteWxZg94mmLjg2KnJYBuSn8kiFPYQ0F5MjE7df4tDDTGJ/VEFIG5
11 | EkQffaNYhW0Z5ORLvW1R1Yd1/ew3UWo+mZ7XAUGLF6clsWSQvzSrrNMYzCk5Fa0L
12 | wvMtQdEVLL3q7/KsEHD7N78EVlmEDlOtC21UidUqXnawCE1QIjAHqFsNNPR2j0lg
13 | OoEjrGdzrvUg6hNV9m6CbSECAwEAAQ==
14 | -----END PUBLIC KEY-----
--------------------------------------------------------------------------------
/packages/dgraph/tests/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | CONTAINER_NAME=next-auth-dgraph
4 | JEST_WATCH=false
5 |
6 | # Is the watch flag passed to the script?
7 | while getopts w flag
8 | do
9 | case "${flag}" in
10 | w) JEST_WATCH=true;;
11 | *) continue;;
12 | esac
13 | done
14 |
15 | # Start db
16 |
17 | docker run -d --rm \
18 | -p 8000:8000 -p 8080:8080 \
19 | --name "${CONTAINER_NAME}" \
20 | dgraph/standalone
21 |
22 | echo "Waiting 15 sec for db to start..." && sleep 15
23 |
24 | head -n -1 src/graphql/schema.gql > tests/test.schema.gql
25 | PUBLIC_KEY=$(sed 's/$/\\n/' tests/public.key | tr -d '\n')
26 | echo "# Dgraph.Authorization {\"VerificationKey\":\"$PUBLIC_KEY\",\"Namespace\":\"https://dgraph.io/jwt/claims\",\"Header\":\"Authorization\",\"Algo\":\"RS256\"}" >> tests/test.schema.gql
27 |
28 | curl -X POST localhost:8080/admin/schema --data-binary '@tests/test.schema.gql'
29 |
30 | printf "\nWaiting 5 sec for schema to be uploaded..." && sleep 5
31 |
32 | if $JEST_WATCH; then
33 | # Run jest in watch mode
34 | npx jest tests --watch
35 | # Only stop the container after jest has been quit
36 | docker stop "${CONTAINER_NAME}"
37 | else
38 | # Always stop container, but exit with 1 when tests are failing
39 | if npx jest tests; then
40 | docker stop "${CONTAINER_NAME}"
41 | else
42 | docker stop "${CONTAINER_NAME}"
43 | fi
44 | fi
45 |
46 | rm tests/test.schema.gql
--------------------------------------------------------------------------------
/packages/dgraph/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "src",
5 | "outDir": "dist"
6 | },
7 | "exclude": ["tests", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/dynamodb/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | # [1.1.0](https://github.com/nextauthjs/adapters/compare/@next-auth/dynamodb-adapter@1.0.2...@next-auth/dynamodb-adapter@1.1.0) (2022-02-02)
7 |
8 | ### Features
9 |
10 | - **dynamodb:** configurable dynamodb keys ([#380](https://github.com/nextauthjs/adapters/issues/380)) ([c9555aa](https://github.com/nextauthjs/adapters/commit/c9555aa33447a365640d6253a0e73d3cb1f64c14))
11 |
12 | ## [1.0.2](https://github.com/nextauthjs/adapters/compare/@next-auth/dynamodb-adapter@1.0.1...@next-auth/dynamodb-adapter@1.0.2) (2022-01-10)
13 |
14 | ### Bug Fixes
15 |
16 | - **dynamo:** Ensure expires attribute is stored as a UNIX timestamp ([#367](https://github.com/nextauthjs/adapters/issues/367)) ([c262110](https://github.com/nextauthjs/adapters/commit/c2621103d01c10929fb3e2b0aef4443d1e2e0be1))
17 |
18 | ## [1.0.1](https://github.com/nextauthjs/adapters/compare/@next-auth/dynamodb-adapter@1.0.0...@next-auth/dynamodb-adapter@1.0.1) (2021-12-06)
19 |
20 | **Note:** Version bump only for package @next-auth/dynamodb-adapter
21 |
22 | ## [0.4.2](https://github.com/nextauthjs/adapters/compare/@next-auth/dynamodb-adapter@0.4.1...@next-auth/dynamodb-adapter@0.4.2) (2021-07-02)
23 |
24 | **Note:** Version bump only for package @next-auth/dynamodb-adapter
25 |
26 | ## [0.4.1](https://github.com/nextauthjs/adapters/compare/@next-auth/dynamodb-adapter@0.4.0...@next-auth/dynamodb-adapter@0.4.1) (2021-06-30)
27 |
28 | **Note:** Version bump only for package @next-auth/dynamodb-adapter
29 |
--------------------------------------------------------------------------------
/packages/dynamodb/jest-dynamodb-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | tables: [
3 | {
4 | TableName: `next-auth`,
5 | KeySchema: [
6 | { AttributeName: "pk", KeyType: "HASH" },
7 | { AttributeName: "sk", KeyType: "RANGE" },
8 | ],
9 | AttributeDefinitions: [
10 | { AttributeName: "sk", AttributeType: "S" },
11 | { AttributeName: "pk", AttributeType: "S" },
12 | { AttributeName: "GSI1PK", AttributeType: "S" },
13 | { AttributeName: "GSI1SK", AttributeType: "S" },
14 | ],
15 | GlobalSecondaryIndexes: [
16 | {
17 | IndexName: "GSI1",
18 | KeySchema: [
19 | { AttributeName: "GSI1PK", KeyType: "HASH" },
20 | { AttributeName: "GSI1SK", KeyType: "RANGE" },
21 | ],
22 | Projection: {
23 | ProjectionType: "ALL",
24 | },
25 | ProvisionedThroughput: {
26 | ReadCapacityUnits: 1,
27 | WriteCapacityUnits: 1,
28 | },
29 | },
30 | ],
31 | ProvisionedThroughput: { ReadCapacityUnits: 1, WriteCapacityUnits: 1 },
32 | },
33 | {
34 | TableName: `next-auth-custom`,
35 | KeySchema: [
36 | { AttributeName: "PK", KeyType: "HASH" },
37 | { AttributeName: "SK", KeyType: "RANGE" },
38 | ],
39 | AttributeDefinitions: [
40 | { AttributeName: "PK", AttributeType: "S" },
41 | { AttributeName: "SK", AttributeType: "S" },
42 | { AttributeName: "gsi1pk", AttributeType: "S" },
43 | { AttributeName: "gsi1sk", AttributeType: "S" },
44 | ],
45 | GlobalSecondaryIndexes: [
46 | {
47 | IndexName: "gsi1",
48 | KeySchema: [
49 | { AttributeName: "gsi1pk", KeyType: "HASH" },
50 | { AttributeName: "gsi1sk", KeyType: "RANGE" },
51 | ],
52 | Projection: {
53 | ProjectionType: "ALL",
54 | },
55 | ProvisionedThroughput: {
56 | ReadCapacityUnits: 1,
57 | WriteCapacityUnits: 1,
58 | },
59 | },
60 | ],
61 | ProvisionedThroughput: { ReadCapacityUnits: 1, WriteCapacityUnits: 1 },
62 | },
63 | // etc
64 | ],
65 | port: 8000,
66 | installerConfig: {
67 | installPath: "./dynamodblocal-bin",
68 | downloadUrl:
69 | "https://s3.eu-central-1.amazonaws.com/dynamodb-local-frankfurt/dynamodb_local_latest.tar.gz",
70 | },
71 | }
72 |
--------------------------------------------------------------------------------
/packages/dynamodb/jest.config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * For a detailed explanation regarding each configuration property and type check, visit:
3 | * https://jestjs.io/docs/en/configuration.html
4 | */
5 | const { defaults: tsjPreset } = require("ts-jest/presets")
6 |
7 | module.exports = {
8 | // Indicates whether the coverage information should be collected while executing the test
9 | collectCoverage: true,
10 | // Indicates which provider should be used to instrument code for coverage
11 | coverageProvider: "v8",
12 | // A preset that is used as a base for Jest's configuration
13 | preset: "@shelf/jest-dynamodb",
14 | transform: {
15 | ...tsjPreset.transform,
16 | },
17 | // The test environment that will be used for testing
18 | testEnvironment: "node",
19 | }
20 |
--------------------------------------------------------------------------------
/packages/dynamodb/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nextauthjs/adapters/1237a5372004951eccb37c5f7481e5fcb62415b6/packages/dynamodb/logo.png
--------------------------------------------------------------------------------
/packages/dynamodb/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@next-auth/dynamodb-adapter",
3 | "repository": "https://github.com/nextauthjs/adapters",
4 | "version": "1.1.0",
5 | "description": "AWS DynamoDB adapter for next-auth.",
6 | "keywords": [
7 | "next-auth",
8 | "next.js",
9 | "oauth",
10 | "dynamodb"
11 | ],
12 | "homepage": "https://next-auth.js.org",
13 | "bugs": {
14 | "url": "https://github.com/nextauthjs/next-auth/issues"
15 | },
16 | "main": "dist/index.js",
17 | "private": false,
18 | "publishConfig": {
19 | "access": "public"
20 | },
21 | "scripts": {
22 | "test:default": "jest",
23 | "test:custom": "CUSTOM_MODEL=1 jest",
24 | "test": "yarn test:default && yarn test:custom",
25 | "build": "tsc"
26 | },
27 | "files": [
28 | "README.md",
29 | "dist"
30 | ],
31 | "author": "Pol Marnette",
32 | "license": "ISC",
33 | "peerDependencies": {
34 | "@aws-sdk/lib-dynamodb": "^3.36.1",
35 | "next-auth": "^4.0.1"
36 | },
37 | "devDependencies": {
38 | "@aws-sdk/client-dynamodb": "^3.36.1",
39 | "@aws-sdk/lib-dynamodb": "^3.36.1",
40 | "@shelf/jest-dynamodb": "^2.1.0"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/dynamodb/src/utils.ts:
--------------------------------------------------------------------------------
1 | // https://github.com/honeinc/is-iso-date/blob/master/index.js
2 | const isoDateRE =
3 | /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/
4 | function isDate(value: any) {
5 | return value && isoDateRE.test(value) && !isNaN(Date.parse(value))
6 | }
7 |
8 | export const format = {
9 | /** Takes a plain old JavaScript object and turns it into a Dynamodb object */
10 | to(object: Record) {
11 | const newObject: Record = {}
12 | for (const key in object) {
13 | const value = object[key]
14 | if (value instanceof Date) {
15 | // DynamoDB requires the TTL attribute be a UNIX timestamp (in secs).
16 | if (key === "expires") newObject[key] = value.getTime() / 1000
17 | else newObject[key] = value.toISOString()
18 | } else newObject[key] = value
19 | }
20 | return newObject
21 | },
22 | /** Takes a Dynamo object and returns a plain old JavaScript object */
23 | from>(
24 | object: Record | undefined,
25 | keys: string[] = ["pk", "sk", "GSI1PK", "GSI1SK"]
26 | ): T | null {
27 | if (!object) return null
28 | const newObject: Record = {}
29 | for (const key in object) {
30 | // Filter DynamoDB table and GSI keys so it doesn't get passed to core,
31 | // to avoid revealing the type of database
32 | if (keys.includes(key)) continue
33 |
34 | const value = object[key]
35 |
36 | if (isDate(value)) newObject[key] = new Date(value)
37 | // hack to keep type property in account
38 | else if (key === "type" && ["SESSION", "VT", "USER"].includes(value))
39 | continue
40 | // The expires property is stored as a UNIX timestamp in seconds, but
41 | // JavaScript needs it in milliseconds, so multiply by 1000.
42 | else if (key === "expires" && typeof value === "number")
43 | newObject[key] = new Date(value * 1000)
44 | else newObject[key] = value
45 | }
46 | return newObject as T
47 | },
48 | }
49 |
50 | export function generateUpdateExpression(object: Record): {
51 | UpdateExpression: string
52 | ExpressionAttributeNames: Record
53 | ExpressionAttributeValues: Record
54 | } {
55 | const formatedSession = format.to(object)
56 | let UpdateExpression = "set"
57 | const ExpressionAttributeNames: Record = {}
58 | const ExpressionAttributeValues: Record = {}
59 | for (const property in formatedSession) {
60 | UpdateExpression += ` #${property} = :${property},`
61 | ExpressionAttributeNames["#" + property] = property
62 | ExpressionAttributeValues[":" + property] = formatedSession[property]
63 | }
64 | UpdateExpression = UpdateExpression.slice(0, -1)
65 | return {
66 | UpdateExpression,
67 | ExpressionAttributeNames,
68 | ExpressionAttributeValues,
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/packages/dynamodb/tests/custom.test.ts:
--------------------------------------------------------------------------------
1 | import type { DynamoDBAdapterOptions } from "../src"
2 | import { DynamoDBAdapter, format } from "../src"
3 | import { runBasicTests } from "../../../basic-tests"
4 | import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
5 | import { DynamoDB } from "@aws-sdk/client-dynamodb"
6 |
7 | const config = {
8 | endpoint: "http://127.0.0.1:8000",
9 | region: "eu-central-1",
10 | tls: false,
11 | credentials: {
12 | accessKeyId: "foo",
13 | secretAccessKey: "bar",
14 | },
15 | }
16 |
17 | export const client = DynamoDBDocument.from(new DynamoDB(config), {
18 | marshallOptions: {
19 | convertEmptyValues: true,
20 | removeUndefinedValues: true,
21 | convertClassInstanceToMap: true,
22 | },
23 | })
24 |
25 | const tableName = "next-auth-custom"
26 | const indexName = "gsi1"
27 | const partitionKey = "PK"
28 | const sortKey = "SK"
29 | const indexPartitionKey = "gsi1pk"
30 | const indexSortKey = "gsi1sk"
31 | const keys = [partitionKey, sortKey, indexPartitionKey, indexSortKey]
32 |
33 | const options: DynamoDBAdapterOptions = {
34 | tableName,
35 | partitionKey,
36 | sortKey,
37 | indexName,
38 | indexPartitionKey,
39 | indexSortKey,
40 | }
41 |
42 | const adapter = DynamoDBAdapter(client, options)
43 | const TableName = tableName
44 | const IndexName = indexName
45 |
46 | runBasicTests({
47 | adapter,
48 | db: {
49 | async user(id) {
50 | const user = await client.get({
51 | TableName,
52 | Key: {
53 | [partitionKey]: `USER#${id}`,
54 | [sortKey]: `USER#${id}`,
55 | },
56 | })
57 |
58 | return format.from(user.Item, keys)
59 | },
60 | async session(token) {
61 | const session = await client.query({
62 | TableName,
63 | IndexName,
64 | KeyConditionExpression: "#gsi1pk = :gsi1pk AND #gsi1sk = :gsi1sk",
65 | ExpressionAttributeNames: {
66 | "#gsi1pk": indexPartitionKey,
67 | "#gsi1sk": indexSortKey,
68 | },
69 | ExpressionAttributeValues: {
70 | ":gsi1pk": `SESSION#${token}`,
71 | ":gsi1sk": `SESSION#${token}`,
72 | },
73 | })
74 |
75 | return format.from(session.Items?.[0], keys)
76 | },
77 | async account({ provider, providerAccountId }) {
78 | const account = await client.query({
79 | TableName,
80 | IndexName,
81 | KeyConditionExpression: "#gsi1pk = :gsi1pk AND #gsi1sk = :gsi1sk",
82 | ExpressionAttributeNames: {
83 | "#gsi1pk": indexPartitionKey,
84 | "#gsi1sk": indexSortKey,
85 | },
86 | ExpressionAttributeValues: {
87 | ":gsi1pk": `ACCOUNT#${provider}`,
88 | ":gsi1sk": `ACCOUNT#${providerAccountId}`,
89 | },
90 | })
91 |
92 | return format.from(account.Items?.[0], keys)
93 | },
94 | async verificationToken({ token, identifier }) {
95 | const vt = await client.get({
96 | TableName,
97 | Key: {
98 | [partitionKey]: `VT#${identifier}`,
99 | [sortKey]: `VT#${token}`,
100 | },
101 | })
102 | return format.from(vt.Item, keys)
103 | },
104 | },
105 | })
106 |
--------------------------------------------------------------------------------
/packages/dynamodb/tests/format.test.ts:
--------------------------------------------------------------------------------
1 | import { format } from "../src/utils"
2 |
3 | describe("dynamodb utils.format", () => {
4 | it("format.to() preserves non-Date non-expires properties", () => {
5 | expect(
6 | format.to({
7 | pk: "test-pk",
8 | email: "test@example.com",
9 | })
10 | ).toEqual({
11 | pk: "test-pk",
12 | email: "test@example.com",
13 | })
14 | })
15 |
16 | it("format.to() converts non-expires Date properties to ISO strings", () => {
17 | const date = new Date()
18 | expect(
19 | format.to({
20 | dateProp: date,
21 | })
22 | ).toEqual({
23 | dateProp: date.toISOString(),
24 | })
25 | })
26 |
27 | it("format.to() converts expires property to a UNIX timestamp", () => {
28 | // DynamoDB requires that the property used for TTL is a UNIX timestamp.
29 | const date = new Date()
30 | const timestamp = date.getTime() / 1000
31 | expect(
32 | format.to({
33 | expires: date,
34 | })
35 | ).toEqual({
36 | expires: timestamp,
37 | })
38 | })
39 |
40 | it("format.from() preserves non-special attributes", () => {
41 | expect(
42 | format.from({
43 | testAttr1: "test-value",
44 | testAttr2: 5,
45 | })
46 | ).toEqual({
47 | testAttr1: "test-value",
48 | testAttr2: 5,
49 | })
50 | })
51 |
52 | it("format.from() removes dynamodb key attributes", () => {
53 | expect(
54 | format.from({
55 | pk: "test-pk",
56 | sk: "test-sk",
57 | GSI1PK: "test-GSI1PK",
58 | GSI1SK: "test-GSI1SK",
59 | })
60 | ).toEqual({})
61 | })
62 |
63 | it("format.from() only removes type attribute from Session, VT, and User", () => {
64 | expect(format.from({ type: "SESSION" })).toEqual({})
65 | expect(format.from({ type: "VT" })).toEqual({})
66 | expect(format.from({ type: "USER" })).toEqual({})
67 | expect(format.from({ type: "ANYTHING" })).toEqual({ type: "ANYTHING" })
68 | expect(format.from({ type: "ELSE" })).toEqual({ type: "ELSE" })
69 | })
70 |
71 | it("format.from() converts ISO strings to Date instances", () => {
72 | const date = new Date()
73 | expect(
74 | format.from({
75 | someDate: date.toISOString(),
76 | })
77 | ).toEqual({
78 | someDate: date,
79 | })
80 | })
81 |
82 | it("format.from() converts expires attribute from timestamp to Date instance", () => {
83 | // AdapterSession["expires"] and VerificationToken["expires"] are both meant
84 | // to be Date instances.
85 | const date = new Date()
86 | const timestamp = date.getTime() / 1000
87 | expect(
88 | format.from({
89 | expires: timestamp,
90 | })
91 | ).toEqual({
92 | expires: date,
93 | })
94 | })
95 |
96 | it("format.from() converts expires attribute from ISO string to Date instance", () => {
97 | // Due to a bug in an old version, some expires attributes were stored as
98 | // ISO strings, so we need to handle those properly too.
99 | const date = new Date()
100 | expect(
101 | format.from({
102 | expires: date.toISOString(),
103 | })
104 | ).toEqual({
105 | expires: date,
106 | })
107 | })
108 |
109 | it("format.from(format.to()) preserves expires attribute", () => {
110 | const date = new Date()
111 | expect(
112 | format.from(
113 | format.to({
114 | expires: date,
115 | })
116 | )
117 | ).toEqual({
118 | expires: date,
119 | })
120 | })
121 | })
122 |
--------------------------------------------------------------------------------
/packages/dynamodb/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | import { DynamoDB } from "@aws-sdk/client-dynamodb"
2 | import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
3 | import { DynamoDBAdapter } from "../src"
4 | import { runBasicTests } from "../../../basic-tests"
5 | import { format } from "../src/"
6 | const config = {
7 | endpoint: "http://127.0.0.1:8000",
8 | region: "eu-central-1",
9 | tls: false,
10 | credentials: {
11 | accessKeyId: "foo",
12 | secretAccessKey: "bar",
13 | },
14 | }
15 |
16 | const client = DynamoDBDocument.from(new DynamoDB(config), {
17 | marshallOptions: {
18 | convertEmptyValues: true,
19 | removeUndefinedValues: true,
20 | convertClassInstanceToMap: true,
21 | },
22 | })
23 |
24 | const adapter = DynamoDBAdapter(client)
25 |
26 | const TableName = "next-auth"
27 |
28 | runBasicTests({
29 | adapter,
30 | db: {
31 | async user(id) {
32 | const user = await client.get({
33 | TableName,
34 | Key: {
35 | pk: `USER#${id}`,
36 | sk: `USER#${id}`,
37 | },
38 | })
39 |
40 | return format.from(user.Item)
41 | },
42 | async session(token) {
43 | const session = await client.query({
44 | TableName,
45 | IndexName: "GSI1",
46 | KeyConditionExpression: "#gsi1pk = :gsi1pk AND #gsi1sk = :gsi1sk",
47 | ExpressionAttributeNames: {
48 | "#gsi1pk": "GSI1PK",
49 | "#gsi1sk": "GSI1SK",
50 | },
51 | ExpressionAttributeValues: {
52 | ":gsi1pk": `SESSION#${token}`,
53 | ":gsi1sk": `SESSION#${token}`,
54 | },
55 | })
56 |
57 | return format.from(session.Items?.[0])
58 | },
59 | async account({ provider, providerAccountId }) {
60 | const account = await client.query({
61 | TableName,
62 | IndexName: "GSI1",
63 | KeyConditionExpression: "#gsi1pk = :gsi1pk AND #gsi1sk = :gsi1sk",
64 | ExpressionAttributeNames: {
65 | "#gsi1pk": "GSI1PK",
66 | "#gsi1sk": "GSI1SK",
67 | },
68 | ExpressionAttributeValues: {
69 | ":gsi1pk": `ACCOUNT#${provider}`,
70 | ":gsi1sk": `ACCOUNT#${providerAccountId}`,
71 | },
72 | })
73 |
74 | return format.from(account.Items?.[0])
75 | },
76 | async verificationToken({ token, identifier }) {
77 | const vt = await client.get({
78 | TableName,
79 | Key: {
80 | pk: `VT#${identifier}`,
81 | sk: `VT#${token}`,
82 | },
83 | })
84 | return format.from(vt.Item)
85 | },
86 | },
87 | })
88 |
--------------------------------------------------------------------------------
/packages/dynamodb/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "src",
5 | "outDir": "dist"
6 | },
7 | "exclude": ["tests", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/fauna/.babelrc.js:
--------------------------------------------------------------------------------
1 | module.exports = require("../../.babelrc.js")
2 |
--------------------------------------------------------------------------------
/packages/fauna/.fauna-migrate.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | directories: {
3 | root: "fauna",
4 | resources: "resources",
5 | migrations: "migrations",
6 | children: "dbs",
7 | temp: "temp",
8 | },
9 | collection: "migrations",
10 | }
11 |
--------------------------------------------------------------------------------
/packages/fauna/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [1.0.2](https://github.com/nextauthjs/adapters/compare/@next-auth/fauna-adapter@1.0.1...@next-auth/fauna-adapter@1.0.2) (2022-01-10)
7 |
8 | ### Bug Fixes
9 |
10 | - **fauna:** Convert `value` prop to `Date` only if of type `string` ([#365](https://github.com/nextauthjs/adapters/issues/365)) ([c8dad2b](https://github.com/nextauthjs/adapters/commit/c8dad2b1bf74ab1574c92ee5fda879d798a43977)), closes [#364](https://github.com/nextauthjs/adapters/issues/364)
11 |
12 | ## [1.0.1](https://github.com/nextauthjs/adapters/compare/@next-auth/fauna-adapter@1.0.0...@next-auth/fauna-adapter@1.0.1) (2021-12-06)
13 |
14 | **Note:** Version bump only for package @next-auth/fauna-adapter
15 |
16 | ## [0.2.4](https://github.com/nextauthjs/adapters/compare/@next-auth/fauna-adapter@0.2.3...@next-auth/fauna-adapter@0.2.4) (2021-10-27)
17 |
18 | ### Reverts
19 |
20 | - Revert "docs(fauna): update `README.md` (#244)" (#246) ([26cd24a](https://github.com/nextauthjs/adapters/commit/26cd24a6eba3d42ed7febd5eb45b13c236c57819)), closes [#244](https://github.com/nextauthjs/adapters/issues/244) [#246](https://github.com/nextauthjs/adapters/issues/246)
21 |
22 | ## [0.2.3](https://github.com/nextauthjs/adapters/compare/@next-auth/fauna-adapter@0.2.2...@next-auth/fauna-adapter@0.2.3) (2021-09-19)
23 |
24 | **Note:** Version bump only for package @next-auth/fauna-adapter
25 |
26 | ## [0.2.2](https://github.com/nextauthjs/adapters/compare/@next-auth/fauna-adapter@0.2.1...@next-auth/fauna-adapter@0.2.2) (2021-07-02)
27 |
28 | **Note:** Version bump only for package @next-auth/fauna-adapter
29 |
30 | ## [0.2.1](https://github.com/nextauthjs/adapters/compare/@next-auth/fauna-adapter@0.2.0...@next-auth/fauna-adapter@0.2.1) (2021-06-30)
31 |
32 | ### Bug Fixes
33 |
34 | - **fauna:** change the name of the index to `verification_request_by_token_and_identifier` ([#157](https://github.com/nextauthjs/adapters/issues/157)) ([01a3c52](https://github.com/nextauthjs/adapters/commit/01a3c5205f30eec57c7b9298b762cccf1f2400fd))
35 |
36 | # [0.2.0](https://github.com/nextauthjs/adapters/compare/@next-auth/fauna-adapter@0.1.0...@next-auth/fauna-adapter@0.2.0) (2021-06-30)
37 |
38 | ### Bug Fixes
39 |
40 | - adapter export function name ([eb6a21a](https://github.com/nextauthjs/adapters/commit/eb6a21a0302ef42a32314e48a75542bade26605e))
41 | - include /dist files in published build ([751ea95](https://github.com/nextauthjs/adapters/commit/751ea95a3b40dc3a94bf4de6253974e1664a2661))
42 | - merge conflicts ([aa48f2f](https://github.com/nextauthjs/adapters/commit/aa48f2f7586345764d0a586df23534f9abc2b53d))
43 | - rm type=module from package.json ([c207348](https://github.com/nextauthjs/adapters/commit/c207348d126a766abe341e6afe36b04d47c6bac6))
44 | - specify module in package.json ([d6e85ce](https://github.com/nextauthjs/adapters/commit/d6e85ce68b0a7d70f6b6078ac8d66e36c4724131))
45 | - test match new export ([ee96664](https://github.com/nextauthjs/adapters/commit/ee966647dadbc649d6a93f5ae4d5fb5deb6f6772))
46 |
47 | ### Features
48 |
49 | - add build step to package.json ([28a4f40](https://github.com/nextauthjs/adapters/commit/28a4f403b07fc115c171623d6801c9392f50bd28))
50 |
--------------------------------------------------------------------------------
/packages/fauna/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Fauna Adapter - NextAuth.js
6 |
7 | Open Source. Full Stack. Own Your Data.
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ## Overview
17 |
18 | This is the Fauna Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
19 |
20 | You can find the Fauna schema and seed information in the docs at [next-auth.js.org/adapters/fauna](https://next-auth.js.org/adapters/fauna).
21 |
22 | ## Getting Started
23 |
24 | 1. Install `faunadb`, `next-auth` and `@next-auth/fauna-adapter`
25 |
26 | ```js
27 | npm install faunadb next-auth @next-auth/fauna-adapter@next
28 | ```
29 |
30 | 2. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
31 |
32 | ```js
33 | import NextAuth from "next-auth"
34 | import { Client as FaunaClient } from "faunadb"
35 | import { FaunaAdapter } from "@next-auth/fauna-adapter"
36 |
37 | const client = new FaunaClient({
38 | secret: "secret",
39 | scheme: "http",
40 | domain: "localhost",
41 | port: 8443,
42 | })
43 |
44 | // For more information on each option (and a full list of options) go to
45 | // https://next-auth.js.org/configuration/options
46 | export default NextAuth({
47 | // https://next-auth.js.org/configuration/providers
48 | providers: [],
49 | adapter: FaunaAdapter(client)
50 | ...
51 | })
52 | ```
53 |
54 | ## Contributing
55 |
56 | We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
57 |
58 | ## License
59 |
60 | ISC
61 |
--------------------------------------------------------------------------------
/packages/fauna/fauna/resources/collections/accounts.fql:
--------------------------------------------------------------------------------
1 | CreateCollection({ name: "accounts" })
--------------------------------------------------------------------------------
/packages/fauna/fauna/resources/collections/sessions.fql:
--------------------------------------------------------------------------------
1 | CreateCollection({ name: "sessions" })
--------------------------------------------------------------------------------
/packages/fauna/fauna/resources/collections/users.fql:
--------------------------------------------------------------------------------
1 | CreateCollection({ name: "users" })
--------------------------------------------------------------------------------
/packages/fauna/fauna/resources/collections/verification_tokens.fql:
--------------------------------------------------------------------------------
1 | CreateCollection({ name: "verification_tokens" })
--------------------------------------------------------------------------------
/packages/fauna/fauna/resources/indexes/account_by_provider_and_provider_account_id.fql:
--------------------------------------------------------------------------------
1 | CreateIndex({
2 | name: "account_by_provider_and_provider_account_id",
3 | source: Collection("accounts"),
4 | unique: true,
5 | terms: [
6 | { field: ["data", "provider"] },
7 | { field: ["data", "providerAccountId"] },
8 | ],
9 | })
--------------------------------------------------------------------------------
/packages/fauna/fauna/resources/indexes/accounts_by_user_id.fql:
--------------------------------------------------------------------------------
1 | CreateIndex({
2 | name: "accounts_by_user_id",
3 | source: Collection("accounts"),
4 | terms: [{ field: ["data", "userId"] }]
5 | })
--------------------------------------------------------------------------------
/packages/fauna/fauna/resources/indexes/session_by_session_token.fql:
--------------------------------------------------------------------------------
1 | CreateIndex({
2 | name: "session_by_session_token",
3 | source: Collection("sessions"),
4 | unique: true,
5 | terms: [{ field: ["data", "sessionToken"] }],
6 | })
--------------------------------------------------------------------------------
/packages/fauna/fauna/resources/indexes/sessions_by_user_id.fql:
--------------------------------------------------------------------------------
1 | CreateIndex({
2 | name: "sessions_by_user_id",
3 | source: Collection("sessions"),
4 | terms: [{ field: ["data", "userId"] }]
5 | })
--------------------------------------------------------------------------------
/packages/fauna/fauna/resources/indexes/user_by_email.fql:
--------------------------------------------------------------------------------
1 | CreateIndex({
2 | name: "user_by_email",
3 | source: Collection("users"),
4 | unique: true,
5 | terms: [{ field: ["data", "email"] }],
6 | })
--------------------------------------------------------------------------------
/packages/fauna/fauna/resources/indexes/verification_token_by_identifier_and_token.fql:
--------------------------------------------------------------------------------
1 | CreateIndex({
2 | name: "verification_token_by_identifier_and_token",
3 | source: Collection("verification_tokens"),
4 | unique: true,
5 | terms: [
6 | { field: ["data", "identifier"] },
7 | { field: ["data", "token"] },
8 | ],
9 | })
--------------------------------------------------------------------------------
/packages/fauna/fauna/schema.fql:
--------------------------------------------------------------------------------
1 | // First run this in the Fauna shell to create the collections
2 | Do(
3 | CreateCollection({ name: "users" }),
4 | CreateCollection({ name: "accounts" }),
5 | CreateCollection({ name: "sessions" }),
6 | CreateCollection({ name: "verification_tokens" })
7 | )
8 |
9 | // Then run this in the Fauna shell to create indexes
10 | Do(
11 | CreateIndex({
12 | name: "accounts_by_user_id",
13 | source: Collection("accounts"),
14 | terms: [{ field: ["data", "userId"] }]
15 | }),
16 | CreateIndex({
17 | name: "session_by_session_token",
18 | source: Collection("sessions"),
19 | unique: true,
20 | terms: [{ field: ["data", "sessionToken"] }],
21 | }),
22 | CreateIndex({
23 | name: "sessions_by_user_id",
24 | source: Collection("sessions"),
25 | terms: [{ field: ["data", "userId"] }]
26 | }),
27 | CreateIndex({
28 | name: "user_by_email",
29 | source: Collection("users"),
30 | unique: true,
31 | terms: [{ field: ["data", "email"] }],
32 | }),
33 | CreateIndex({
34 | name: "account_by_provider_and_provider_account_id",
35 | source: Collection("accounts"),
36 | unique: true,
37 | terms: [
38 | { field: ["data", "provider"] },
39 | { field: ["data", "providerAccountId"] },
40 | ],
41 | }),
42 | CreateIndex({
43 | name: "verification_token_by_identifier_and_token",
44 | source: Collection("verification_tokens"),
45 | unique: true,
46 | terms: [
47 | { field: ["data", "identifier"] },
48 | { field: ["data", "token"] },
49 | ],
50 | })
51 | )
--------------------------------------------------------------------------------
/packages/fauna/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ...require("../../jest.config"),
3 | transform: {
4 | "^.+\\.jsx?$": "babel-jest",
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/packages/fauna/logo.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/packages/fauna/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@next-auth/fauna-adapter",
3 | "version": "1.0.2",
4 | "description": "Fauna Adapter for NextAuth",
5 | "homepage": "https://next-auth.js.org",
6 | "repository": "https://github.com/nextauthjs/adapters",
7 | "bugs": {
8 | "url": "https://github.com/nextauthjs/next-auth/issues"
9 | },
10 | "files": [
11 | "dist",
12 | "README.md"
13 | ],
14 | "author": "Bhanu Teja P",
15 | "contributors": [
16 | {
17 | "name": "Nico Domino",
18 | "email": "yo@ndo.dev"
19 | },
20 | {
21 | "name": "Balázs Orbán",
22 | "email": "info@balazsorban.com"
23 | }
24 | ],
25 | "main": "dist/index.js",
26 | "license": "ISC",
27 | "keywords": [
28 | "next-auth",
29 | "next.js",
30 | "fauna",
31 | "faunadb"
32 | ],
33 | "private": false,
34 | "publishConfig": {
35 | "access": "public"
36 | },
37 | "scripts": {
38 | "migrate": "fauna-schema-migrate generate",
39 | "build": "tsc",
40 | "test": "./tests/test.sh"
41 | },
42 | "peerDependencies": {
43 | "faunadb": "^4.3.0",
44 | "next-auth": "^4.0.1"
45 | },
46 | "devDependencies": {
47 | "@fauna-labs/fauna-schema-migrate": "^2.1.3",
48 | "faunadb": "^4.3.0"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/packages/fauna/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | import { collections, FaunaAdapter, format, indexes, query } from "../src"
2 | import { runBasicTests } from "../../../basic-tests"
3 | import { Client as FaunaClient, Get, Match, Ref } from "faunadb"
4 |
5 | const client = new FaunaClient({
6 | secret: "secret",
7 | scheme: "http",
8 | domain: "localhost",
9 | port: 8443,
10 | })
11 |
12 | const q = query(client, format.from)
13 |
14 | runBasicTests({
15 | adapter: FaunaAdapter(client),
16 | db: {
17 | disconnect: async () => await client.close({ force: true }),
18 | user: async (id) => await q(Get(Ref(collections.Users, id))),
19 | session: async (sessionToken) =>
20 | await q(Get(Match(indexes.SessionByToken, sessionToken))),
21 | async account({ provider, providerAccountId }) {
22 | const key = [provider, providerAccountId]
23 | const ref = Match(indexes.AccountByProviderAndProviderAccountId, key)
24 | return await q(Get(ref))
25 | },
26 | async verificationToken({ identifier, token }) {
27 | const key = [identifier, token]
28 | const ref = Match(indexes.VerificationTokenByIdentifierAndToken, key)
29 | const verificationToken = await q(Get(ref))
30 | // @ts-expect-error
31 | if (verificationToken) delete verificationToken.id
32 | return verificationToken
33 | },
34 | },
35 | })
36 |
--------------------------------------------------------------------------------
/packages/fauna/tests/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | CONTAINER_NAME=next-auth-fauna-test
4 | export FAUNADB_PORT=8443
5 | export FAUNA_ADMIN_KEY=secret
6 | export FAUNADB_DOMAIN=localhost
7 | export FAUNADB_SCHEME=http
8 |
9 |
10 | # Start db
11 | docker run -d --rm \
12 | --name ${CONTAINER_NAME} \
13 | -p ${FAUNADB_PORT}:${FAUNADB_PORT} \
14 | fauna/faunadb
15 |
16 | echo "Waiting 20 sec for db to start..."
17 | sleep 20
18 |
19 | # Create tables and indeces
20 | npx fauna-schema-migrate generate
21 | npx fauna-schema-migrate apply all
22 |
23 | # Always stop container, but exit with 1 when tests are failing
24 | if npx jest;then
25 | docker stop ${CONTAINER_NAME}
26 | else
27 | docker stop ${CONTAINER_NAME} && exit 1
28 | fi
29 |
--------------------------------------------------------------------------------
/packages/fauna/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "src",
5 | "outDir": "dist"
6 | },
7 | "exclude": ["tests", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/firebase/.firebaserc:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/packages/firebase/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | firebase-debug.log*
8 | firebase-debug.*.log*
9 |
10 | # Firebase cache
11 | .firebase/
12 |
13 | # Firebase config
14 |
15 | # Uncomment this if you'd like others to create their own Firebase project.
16 | # For a team working on the same Firebase project(s), it is recommended to leave
17 | # it commented so all members can deploy to the same project(s) in .firebaserc.
18 | # .firebaserc
19 |
20 | # Runtime data
21 | pids
22 | *.pid
23 | *.seed
24 | *.pid.lock
25 |
26 | # Directory for instrumented libs generated by jscoverage/JSCover
27 | lib-cov
28 |
29 | # Coverage directory used by tools like istanbul
30 | coverage
31 |
32 | # nyc test coverage
33 | .nyc_output
34 |
35 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
36 | .grunt
37 |
38 | # Bower dependency directory (https://bower.io/)
39 | bower_components
40 |
41 | # node-waf configuration
42 | .lock-wscript
43 |
44 | # Compiled binary addons (http://nodejs.org/api/addons.html)
45 | build/Release
46 |
47 | # Dependency directories
48 | node_modules/
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Optional REPL history
57 | .node_repl_history
58 |
59 | # Output of 'npm pack'
60 | *.tgz
61 |
62 | # Yarn Integrity file
63 | .yarn-integrity
64 |
65 | # dotenv environment variables file
66 | .env
67 |
--------------------------------------------------------------------------------
/packages/firebase/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [0.1.3](https://github.com/nextauthjs/adapters/compare/@next-auth/firebase-adapter@0.1.2...@next-auth/firebase-adapter@0.1.3) (2021-08-17)
7 |
8 | **Note:** Version bump only for package @next-auth/firebase-adapter
9 |
10 | ## [0.1.2](https://github.com/nextauthjs/adapters/compare/@next-auth/firebase-adapter@0.1.1...@next-auth/firebase-adapter@0.1.2) (2021-07-02)
11 |
12 | **Note:** Version bump only for package @next-auth/firebase-adapter
13 |
14 | ## [0.1.1](https://github.com/nextauthjs/adapters/compare/@next-auth/firebase-adapter@0.1.0...@next-auth/firebase-adapter@0.1.1) (2021-06-30)
15 |
16 | **Note:** Version bump only for package @next-auth/firebase-adapter
17 |
--------------------------------------------------------------------------------
/packages/firebase/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 
5 |
Firebase Adapter - NextAuth.js
6 |
7 | Open Source. Full Stack. Own Your Data.
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ## Overview
17 |
18 | This is the Firebase Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
19 |
20 | You can find more Firebase information in the docs at [next-auth.js.org/adapters/firebase](https://next-auth.js.org/adapters/firebase).
21 |
22 | ## Getting Started
23 |
24 | 1. Install `next-auth` and `@next-auth/firebase-adapter`.
25 |
26 | ```js
27 | npm install next-auth @next-auth/firebase-adapter
28 | ```
29 |
30 | 2. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
31 |
32 | ```js
33 | import NextAuth from "next-auth"
34 | import Providers from "next-auth/providers"
35 | import { FirebaseAdapter } from "@next-auth/firebase-adapter"
36 |
37 | import firebase from "firebase/app"
38 | import "firebase/firestore"
39 |
40 | const firestore = (
41 | firebase.apps[0] ?? firebase.initializeApp(/* your config */)
42 | ).firestore()
43 |
44 | // For more information on each option (and a full list of options) go to
45 | // https://next-auth.js.org/configuration/options
46 | export default NextAuth({
47 | // https://next-auth.js.org/configuration/providers
48 | providers: [
49 | Providers.Google({
50 | clientId: process.env.GOOGLE_ID,
51 | clientSecret: process.env.GOOGLE_SECRET,
52 | }),
53 | ],
54 | adapter: FirebaseAdapter(firestore),
55 | ...
56 | })
57 | ```
58 |
59 | ## Options
60 |
61 | When initializing the firestore adapter, you must pass in the firebase config object with the details from your project. More details on how to obtain that config object can be found [here](https://support.google.com/firebase/answer/7015592).
62 |
63 | An example firebase config looks like this:
64 |
65 | ```js
66 | const firebaseConfig = {
67 | apiKey: "AIzaSyDOCAbC123dEf456GhI789jKl01-MnO",
68 | authDomain: "myapp-project-123.firebaseapp.com",
69 | databaseURL: "https://myapp-project-123.firebaseio.com",
70 | projectId: "myapp-project-123",
71 | storageBucket: "myapp-project-123.appspot.com",
72 | messagingSenderId: "65211879809",
73 | appId: "1:65211879909:web:3ae38ef1cdcb2e01fe5f0c",
74 | measurementId: "G-8GSGZQ44ST",
75 | }
76 | ```
77 |
78 | See [firebase.google.com/docs/web/setup](https://firebase.google.com/docs/web/setup) for more details.
79 |
80 | > **From Firebase - Caution**: We do not recommend manually modifying an app's Firebase config file or object. If you initialize an app with invalid or missing values for any of these required "Firebase options", then your end users may experience serious issues.
81 | >
82 | > For open source projects, we generally do not recommend including the app's Firebase config file or object in source control because, in most cases, your users should create their own Firebase projects and point their apps to their own Firebase resources (via their own Firebase config file or object).
83 |
84 | ## Contributing
85 |
86 | We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
87 |
88 | ## License
89 |
90 | ISC
91 |
--------------------------------------------------------------------------------
/packages/firebase/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "emulators": {
3 | "firestore": {
4 | "port": 8080
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/firebase/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("../../jest.config")
2 |
--------------------------------------------------------------------------------
/packages/firebase/logo.svg:
--------------------------------------------------------------------------------
1 |
37 |
--------------------------------------------------------------------------------
/packages/firebase/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@next-auth/firebase-adapter",
3 | "version": "0.1.3",
4 | "description": "Firebase adapter for next-auth.",
5 | "homepage": "https://next-auth.js.org",
6 | "repository": "https://github.com/nextauthjs/adapters",
7 | "bugs": {
8 | "url": "https://github.com/nextauthjs/adapters/issues"
9 | },
10 | "author": "Ron Houben ",
11 | "contributors": [
12 | "Nico Domino ",
13 | "Alex Meuer "
14 | ],
15 | "main": "dist/index.js",
16 | "files": [
17 | "dist",
18 | "index.d.ts"
19 | ],
20 | "license": "ISC",
21 | "keywords": [
22 | "next-auth",
23 | "next.js",
24 | "firebase"
25 | ],
26 | "private": false,
27 | "publishConfig": {
28 | "access": "public"
29 | },
30 | "scripts": {
31 | "build": "tsc",
32 | "test": "FIRESTORE_EMULATOR_HOST=localhost:8080 firebase emulators:exec --only firestore --project next-auth-test jest"
33 | },
34 | "peerDependencies": {
35 | "firebase": "^8.6.2",
36 | "next-auth": "latest"
37 | },
38 | "devDependencies": {
39 | "firebase": "^8.6.2",
40 | "firebase-tools": "^9.11.0"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/firebase/src/utils.ts:
--------------------------------------------------------------------------------
1 | import type firebase from "firebase"
2 |
3 | /**
4 | * Takes in a snapshot and returns all of its `data()`,
5 | * as well as `id` and `createdAt` and `updatedAt` `Date`
6 | */
7 | export function docSnapshotToObject(
8 | snapshot: firebase.firestore.DocumentSnapshot
9 | ): T | null {
10 | if (!snapshot.exists) {
11 | return null
12 | }
13 | const data: any = snapshot.data()
14 | if (data.expires) {
15 | data.expires = data.expires.toDate()
16 | }
17 | return { id: snapshot.id, ...data }
18 | }
19 |
20 | export function querySnapshotToObject(
21 | snapshot: firebase.firestore.QuerySnapshot
22 | ): T | null {
23 | if (snapshot.empty) {
24 | return null
25 | }
26 | const doc = snapshot.docs[0]
27 |
28 | const data: any = doc.data()
29 | if (data.expires) {
30 | data.expires = data.expires.toDate()
31 | }
32 | return { id: doc.id, ...data }
33 | }
34 |
35 | /** Firebase does not like `undefined` values */
36 | export function stripUndefined(obj: any) {
37 | return Object.fromEntries(
38 | Object.entries(obj).filter(([, value]) => typeof value !== "undefined")
39 | )
40 | }
41 |
--------------------------------------------------------------------------------
/packages/firebase/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | import { runBasicTests } from "../../../basic-tests"
2 | import { FirebaseAdapter } from "../src"
3 | import { docSnapshotToObject, querySnapshotToObject } from "../src/utils"
4 |
5 | import firebase from "firebase/app"
6 | import "firebase/firestore"
7 |
8 | const firestore = (
9 | firebase.apps[0] ?? firebase.initializeApp({ projectId: "next-auth-test" })
10 | ).firestore()
11 | firestore.useEmulator("localhost", 8080)
12 |
13 | runBasicTests({
14 | adapter: FirebaseAdapter(firestore),
15 | db: {
16 | async disconnect() {
17 | await firestore.terminate()
18 | },
19 | async session(sessionToken) {
20 | const snapshot = await firestore
21 | .collection("sessions")
22 | .where("sessionToken", "==", sessionToken)
23 | .limit(1)
24 | .get()
25 | return querySnapshotToObject(snapshot)
26 | },
27 | async expireSession(sessionToken, expires) {
28 | const snapshot = await firestore
29 | .collection("sessions")
30 | .where("sessionToken", "==", sessionToken)
31 | .limit(1)
32 | .get()
33 |
34 | if (snapshot.empty) {
35 | console.error(sessionToken, expires)
36 | throw new Error("Could not expire session")
37 | }
38 |
39 | return await firestore
40 | .collection("sessions")
41 | .doc(snapshot.docs[0].id)
42 | .update({ expires })
43 | },
44 | async user(id) {
45 | const snapshot = await firestore.collection("users").doc(id).get()
46 | return docSnapshotToObject(snapshot)
47 | },
48 | async account(providerId, providerAccountId) {
49 | const snapshot = await firestore
50 | .collection("accounts")
51 | .where("providerId", "==", providerId)
52 | .where("providerAccountId", "==", providerAccountId)
53 | .limit(1)
54 | .get()
55 | return querySnapshotToObject(snapshot)
56 | },
57 | async verificationRequest(identifier, token) {
58 | const snapshot = await firestore
59 | .collection("verificationRequests")
60 | .where("identifier", "==", identifier)
61 | .where("token", "==", token)
62 | .limit(1)
63 | .get()
64 | return querySnapshotToObject(snapshot)
65 | },
66 | },
67 | })
68 |
--------------------------------------------------------------------------------
/packages/firebase/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "src",
5 | "outDir": "dist"
6 | },
7 | "exclude": ["tests", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/mikro-orm/.gitignore:
--------------------------------------------------------------------------------
1 | db.sqlite*
2 |
--------------------------------------------------------------------------------
/packages/mikro-orm/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [1.0.1](https://github.com/nextauthjs/adapters/compare/@next-auth/mikro-orm-adapter@1.0.0...@next-auth/mikro-orm-adapter@1.0.1) (2021-12-06)
7 |
8 | **Note:** Version bump only for package @next-auth/mikro-orm-adapter
9 |
--------------------------------------------------------------------------------
/packages/mikro-orm/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Mikro ORM Adapter - NextAuth.js
5 |
6 | Open Source. Full Stack. Own Your Data.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | ## Overview
16 |
17 | This is the MikroORM Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
18 |
19 | ## Getting Started
20 |
21 | 1. Install `next-auth` and `@next-auth/mikro-orm-adapter`
22 |
23 | ```js
24 | npm install next-auth @next-auth/mikro-orm-adapter@next
25 | ```
26 |
27 | 2. Add this adapter to your `pages/api/[...nextauth].ts` next-auth configuration object.
28 |
29 | ```typescript title="pages/api/auth/[...nextauth].ts"
30 | import NextAuth from "next-auth"
31 | import { MikroOrmAdapter } from "@next-auth/mikro-orm-adapter"
32 |
33 | // For more information on each option (and a full list of options) go to
34 | // https://next-auth.js.org/configuration/options
35 | export default NextAuth({
36 | // https://next-auth.js.org/configuration/providers
37 | providers: [],
38 | // optionally pass extended models as { entities: { } }
39 | adapter: MikroOrmAdapter({
40 | dbName: "./db.sqlite",
41 | type: "sqlite",
42 | debug: process.env.DEBUG === "true" || process.env.DEBUG?.includes("db"),
43 | ...
44 | }),
45 | ...
46 | });
47 | ```
48 |
49 | ## Contributing
50 |
51 | We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
52 |
53 | ## License
54 |
55 | ISC
56 |
--------------------------------------------------------------------------------
/packages/mikro-orm/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("../../jest.config")
2 |
--------------------------------------------------------------------------------
/packages/mikro-orm/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@next-auth/mikro-orm-adapter",
3 | "version": "1.0.1",
4 | "description": "MikroORM adapter for next-auth.",
5 | "homepage": "https://next-auth.js.org",
6 | "repository": "https://github.com/nextauthjs/adapters",
7 | "bugs": {
8 | "url": "https://github.com/nextauthjs/next-auth/issues"
9 | },
10 | "author": "Jonas Strassel ",
11 | "contributors": [
12 | "Balázs Orbán "
13 | ],
14 | "main": "dist/index.js",
15 | "license": "ISC",
16 | "keywords": [
17 | "next-auth",
18 | "next.js",
19 | "oauth",
20 | "mikro-orm"
21 | ],
22 | "private": false,
23 | "publishConfig": {
24 | "access": "public"
25 | },
26 | "scripts": {
27 | "test": "jest --runInBand",
28 | "build": "tsc"
29 | },
30 | "files": [
31 | "README.md",
32 | "dist"
33 | ],
34 | "peerDependencies": {
35 | "@mikro-orm/core": ">5 || 5.0.0-dev.527 - 5.0.0-dev.x",
36 | "next-auth": "^4.0.1"
37 | },
38 | "devDependencies": {
39 | "@mikro-orm/core": "^5.0.0-dev.527",
40 | "@mikro-orm/sqlite": "^5.0.0-dev.527"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/mikro-orm/src/entities.ts:
--------------------------------------------------------------------------------
1 | import { v4 as randomUUID } from "uuid"
2 |
3 | import {
4 | Property,
5 | Unique,
6 | PrimaryKey,
7 | Entity,
8 | Enum,
9 | OneToMany,
10 | Collection,
11 | ManyToOne,
12 | } from "@mikro-orm/core"
13 | import type { DefaultAccount } from "next-auth"
14 | import type {
15 | AdapterSession,
16 | AdapterUser,
17 | VerificationToken as AdapterVerificationToken,
18 | } from "next-auth/adapters"
19 | import type { ProviderType } from "next-auth/providers"
20 |
21 | type RemoveIndex = {
22 | // eslint-disable-next-line @typescript-eslint/ban-types
23 | [K in keyof T as {} extends Record ? never : K]: T[K]
24 | }
25 |
26 | @Entity()
27 | export class User implements RemoveIndex {
28 | @PrimaryKey()
29 | id: string = randomUUID()
30 |
31 | @Property({ nullable: true })
32 | name?: string
33 |
34 | @Property({ nullable: true })
35 | @Unique()
36 | email?: string
37 |
38 | @Property({ type: "Date", nullable: true })
39 | emailVerified: Date | null = null
40 |
41 | @Property({ nullable: true })
42 | image?: string
43 |
44 | @OneToMany({
45 | entity: () => Session,
46 | mappedBy: (session) => session.user,
47 | hidden: true,
48 | orphanRemoval: true,
49 | })
50 | sessions = new Collection(this)
51 |
52 | @OneToMany({
53 | entity: () => Account,
54 | mappedBy: (account) => account.user,
55 | hidden: true,
56 | orphanRemoval: true,
57 | })
58 | accounts = new Collection(this)
59 | }
60 |
61 | @Entity()
62 | export class Session implements AdapterSession {
63 | @PrimaryKey()
64 | id: string = randomUUID()
65 |
66 | @ManyToOne({
67 | entity: () => User,
68 | hidden: true,
69 | onDelete: "cascade",
70 | })
71 | user!: User
72 |
73 | @Property({ persist: false })
74 | userId!: string
75 |
76 | @Property()
77 | expires!: Date
78 |
79 | @Property()
80 | @Unique()
81 | sessionToken!: string
82 | }
83 |
84 | @Entity()
85 | @Unique({ properties: ["provider", "providerAccountId"] })
86 | export class Account implements RemoveIndex {
87 | @PrimaryKey()
88 | id: string = randomUUID()
89 |
90 | @ManyToOne({
91 | entity: () => User,
92 | hidden: true,
93 | onDelete: "cascade",
94 | })
95 | user!: User
96 |
97 | @Property({ persist: false })
98 | userId!: string
99 |
100 | @Enum()
101 | type!: ProviderType
102 |
103 | @Property()
104 | provider!: string
105 |
106 | @Property()
107 | providerAccountId!: string
108 |
109 | @Property({ nullable: true })
110 | refresh_token?: string
111 |
112 | @Property({ nullable: true })
113 | access_token?: string
114 |
115 | @Property({ nullable: true })
116 | expires_at?: number
117 |
118 | @Property({ nullable: true })
119 | token_type?: string
120 |
121 | @Property({ nullable: true })
122 | scope?: string
123 |
124 | @Property({ nullable: true })
125 | id_token?: string
126 |
127 | @Property({ nullable: true })
128 | session_state?: string
129 | }
130 |
131 | @Entity()
132 | @Unique({ properties: ["token", "identifier"] })
133 | export class VerificationToken implements AdapterVerificationToken {
134 | @PrimaryKey()
135 | @Property()
136 | token!: string
137 |
138 | @Property()
139 | expires!: Date
140 |
141 | @Property()
142 | identifier!: string
143 | }
144 |
--------------------------------------------------------------------------------
/packages/mikro-orm/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | import { MikroORM, wrap } from "@mikro-orm/core"
2 | import { runBasicTests } from "../../../basic-tests"
3 | import { MikroOrmAdapter, defaultEntities } from "../src"
4 | import { User, VeryImportantEntity } from "./testEntities"
5 |
6 | let _init: MikroORM
7 |
8 | const entities = [
9 | User,
10 | defaultEntities.Account,
11 | defaultEntities.Session,
12 | defaultEntities.VerificationToken,
13 | VeryImportantEntity,
14 | ]
15 |
16 | async function getORM() {
17 | if (_init) return _init
18 |
19 | _init = await MikroORM.init({
20 | dbName: "./db.sqlite",
21 | type: "sqlite",
22 | entities,
23 | debug: process.env.DEBUG === "true" || process.env.DEBUG?.includes("db"),
24 | })
25 | return _init
26 | }
27 |
28 | runBasicTests({
29 | adapter: MikroOrmAdapter(
30 | {
31 | dbName: "./db.sqlite",
32 | type: "sqlite",
33 | entities: [
34 | defaultEntities.User,
35 | defaultEntities.Account,
36 | defaultEntities.Session,
37 | defaultEntities.VerificationToken,
38 | VeryImportantEntity,
39 | ],
40 | debug: process.env.DEBUG === "true" || process.env.DEBUG?.includes("db"),
41 | },
42 | { entities: { User } }
43 | ),
44 | db: {
45 | async connect() {
46 | const orm = await getORM()
47 | await orm.getSchemaGenerator().dropSchema()
48 | await orm.getSchemaGenerator().createSchema()
49 | },
50 | async disconnect() {
51 | const orm = await getORM()
52 | // its fine to tear down the connection if it has been already closed
53 | await orm
54 | .getSchemaGenerator()
55 | .dropSchema()
56 | .catch(() => null)
57 | await orm.close().catch(() => null)
58 | },
59 | async verificationToken(identifier_token) {
60 | const orm = await getORM()
61 | const token = await orm.em
62 | .fork()
63 | .findOne(defaultEntities.VerificationToken, identifier_token)
64 | if (!token) return null
65 | return wrap(token).toObject()
66 | },
67 | async user(id) {
68 | const orm = await getORM()
69 | const user = await orm.em.fork().findOne(defaultEntities.User, { id })
70 | if (!user) return null
71 | return wrap(user).toObject()
72 | },
73 | async account(provider_providerAccountId) {
74 | const orm = await getORM()
75 | const account = await orm.em
76 | .fork()
77 | .findOne(defaultEntities.Account, { ...provider_providerAccountId })
78 | if (!account) return null
79 | return wrap(account).toObject()
80 | },
81 | async session(sessionToken) {
82 | const orm = await getORM()
83 | const session = await orm.em
84 | .fork()
85 | .findOne(defaultEntities.Session, { sessionToken })
86 | if (!session) return null
87 | return wrap(session).toObject()
88 | },
89 | },
90 | })
91 |
--------------------------------------------------------------------------------
/packages/mikro-orm/tests/testEntities.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Cascade,
3 | Collection,
4 | Entity,
5 | OneToMany,
6 | PrimaryKey,
7 | Property,
8 | Unique,
9 | } from "@mikro-orm/core"
10 | import { randomUUID } from "../../../basic-tests"
11 | import type { defaultEntities } from "../src"
12 | import { Account, Session } from "../src/entities"
13 |
14 | @Entity()
15 | export class User implements defaultEntities.User {
16 | @PrimaryKey()
17 | id: string = randomUUID()
18 |
19 | @Property({ nullable: true })
20 | name?: string
21 |
22 | @Property({ nullable: true })
23 | @Unique()
24 | email?: string
25 |
26 | @Property({ type: "Date", nullable: true })
27 | emailVerified: Date | null = null
28 |
29 | @Property({ nullable: true })
30 | image?: string
31 |
32 | @OneToMany({
33 | entity: () => Session,
34 | mappedBy: (session) => session.user,
35 | hidden: true,
36 | orphanRemoval: true,
37 | cascade: [Cascade.ALL],
38 | })
39 | sessions = new Collection(this)
40 |
41 | @OneToMany({
42 | entity: () => Account,
43 | mappedBy: (account) => account.user,
44 | hidden: true,
45 | orphanRemoval: true,
46 | cascade: [Cascade.ALL],
47 | })
48 | accounts = new Collection(this)
49 |
50 | @Property({ hidden: true })
51 | role = "ADMIN"
52 | }
53 |
54 | @Entity()
55 | export class VeryImportantEntity {
56 | @PrimaryKey()
57 | id: string = randomUUID()
58 |
59 | @Property()
60 | important = true
61 | }
62 |
--------------------------------------------------------------------------------
/packages/mikro-orm/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "experimentalDecorators": true,
5 | "emitDecoratorMetadata": true,
6 | "esModuleInterop": true,
7 | "rootDir": "src",
8 | "outDir": "dist",
9 | "stripInternal": true
10 | },
11 | "exclude": ["tests", "dist"]
12 | }
13 |
--------------------------------------------------------------------------------
/packages/mongodb/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [1.0.1](https://github.com/nextauthjs/adapters/compare/@next-auth/mongodb-adapter@1.0.0...@next-auth/mongodb-adapter@1.0.1) (2021-12-06)
7 |
8 | **Note:** Version bump only for package @next-auth/mongodb-adapter
9 |
--------------------------------------------------------------------------------
/packages/mongodb/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
MongoDB Adapter - NextAuth.js
5 |
6 | Open Source. Full Stack. Own Your Data.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | ## Overview
16 |
17 | This is the MongoDB Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
18 |
19 | ## Getting Started
20 |
21 | 1. Install `mongodb`, `next-auth` and `@next-auth/mongodb-adapter`
22 |
23 | ```js
24 | npm install mongodb next-auth @next-auth/mongodb-adapter@next
25 | ```
26 |
27 | 2. Add `lib/mongodb.js`
28 |
29 | ```js
30 | // This approach is taken from https://github.com/vercel/next.js/tree/canary/examples/with-mongodb
31 | import { MongoClient } from "mongodb"
32 |
33 | const uri = process.env.MONGODB_URI
34 | const options = {
35 | useUnifiedTopology: true,
36 | useNewUrlParser: true,
37 | }
38 |
39 | let client
40 | let clientPromise
41 |
42 | if (!process.env.MONGODB_URI) {
43 | throw new Error("Please add your Mongo URI to .env.local")
44 | }
45 |
46 | if (process.env.NODE_ENV === "development") {
47 | // In development mode, use a global variable so that the value
48 | // is preserved across module reloads caused by HMR (Hot Module Replacement).
49 | if (!global._mongoClientPromise) {
50 | client = new MongoClient(uri, options)
51 | global._mongoClientPromise = client.connect()
52 | }
53 | clientPromise = global._mongoClientPromise
54 | } else {
55 | // In production mode, it's best to not use a global variable.
56 | client = new MongoClient(uri, options)
57 | clientPromise = client.connect()
58 | }
59 |
60 | // Export a module-scoped MongoClient promise. By doing this in a
61 | // separate module, the client can be shared across functions.
62 | export default clientPromise
63 | ```
64 |
65 | 3. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
66 |
67 | ```js
68 | import NextAuth from "next-auth"
69 | import { MongoDBAdapter } from "@next-auth/mongodb-adapter"
70 | import clientPromise from "lib/mongodb"
71 |
72 | // For more information on each option (and a full list of options) go to
73 | // https://next-auth.js.org/configuration/options
74 | export default NextAuth({
75 | adapter: MongoDBAdapter(clientPromise),
76 | ...
77 | })
78 | ```
79 |
80 | ## Contributing
81 |
82 | We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
83 |
84 | ## License
85 |
86 | ISC
87 |
--------------------------------------------------------------------------------
/packages/mongodb/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("../../jest.config")
2 |
--------------------------------------------------------------------------------
/packages/mongodb/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@next-auth/mongodb-adapter",
3 | "version": "1.0.1",
4 | "description": "mongoDB adapter for next-auth.",
5 | "homepage": "https://next-auth.js.org",
6 | "repository": "https://github.com/nextauthjs/adapters",
7 | "bugs": {
8 | "url": "https://github.com/nextauthjs/next-auth/issues"
9 | },
10 | "author": "Balázs Orbán ",
11 | "main": "dist/index.js",
12 | "license": "ISC",
13 | "keywords": [
14 | "next-auth",
15 | "next.js",
16 | "oauth",
17 | "mongodb",
18 | "adapter"
19 | ],
20 | "private": false,
21 | "publishConfig": {
22 | "access": "public"
23 | },
24 | "scripts": {
25 | "test": "./tests/test.sh",
26 | "build": "tsc"
27 | },
28 | "files": [
29 | "README.md",
30 | "dist"
31 | ],
32 | "peerDependencies": {
33 | "mongodb": "^4.1.1",
34 | "next-auth": "^4.0.1"
35 | },
36 | "devDependencies": {
37 | "mongodb": "^4.1.1"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/mongodb/tests/custom.test.ts:
--------------------------------------------------------------------------------
1 | import { runBasicTests } from "../../../basic-tests"
2 | import { defaultCollections, format, MongoDBAdapter, _id } from "../src"
3 | import { MongoClient } from "mongodb"
4 | const name = "custom-test"
5 | const client = new MongoClient(`mongodb://localhost:27017/${name}`)
6 | const clientPromise = client.connect()
7 |
8 | const collections = { ...defaultCollections, Users: "some_userz" }
9 |
10 | runBasicTests({
11 | adapter: MongoDBAdapter(clientPromise, {
12 | collections,
13 | }),
14 | db: {
15 | async disconnect() {
16 | await client.db().dropDatabase()
17 | await client.close()
18 | },
19 | async user(id) {
20 | const user = await client
21 | .db()
22 | .collection(collections.Users)
23 | .findOne({ _id: _id(id) })
24 |
25 | if (!user) return null
26 | return format.from(user)
27 | },
28 | async account(provider_providerAccountId) {
29 | const account = await client
30 | .db()
31 | .collection(collections.Accounts)
32 | .findOne(provider_providerAccountId)
33 | if (!account) return null
34 | return format.from(account)
35 | },
36 | async session(sessionToken) {
37 | const session = await client
38 | .db()
39 | .collection(collections.Sessions)
40 | .findOne({ sessionToken })
41 | if (!session) return null
42 | return format.from(session)
43 | },
44 | async verificationToken(identifier_token) {
45 | const token = await client
46 | .db()
47 | .collection(collections.VerificationTokens)
48 | .findOne(identifier_token)
49 | if (!token) return null
50 | const { _id, ...rest } = token
51 | return rest
52 | },
53 | },
54 | })
55 |
--------------------------------------------------------------------------------
/packages/mongodb/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | import { runBasicTests } from "../../../basic-tests"
2 | import { defaultCollections, format, MongoDBAdapter, _id } from "../src"
3 | import { MongoClient } from "mongodb"
4 |
5 | const name = "test"
6 | const client = new MongoClient(`mongodb://localhost:27017/${name}`)
7 | const clientPromise = client.connect()
8 |
9 | runBasicTests({
10 | adapter: MongoDBAdapter(clientPromise),
11 | db: {
12 | async disconnect() {
13 | await client.db().dropDatabase()
14 | await client.close()
15 | },
16 | async user(id) {
17 | const user = await client
18 | .db()
19 | .collection(defaultCollections.Users)
20 | .findOne({ _id: _id(id) })
21 |
22 | if (!user) return null
23 | return format.from(user)
24 | },
25 | async account(provider_providerAccountId) {
26 | const account = await client
27 | .db()
28 | .collection(defaultCollections.Accounts)
29 | .findOne(provider_providerAccountId)
30 | if (!account) return null
31 | return format.from(account)
32 | },
33 | async session(sessionToken) {
34 | const session = await client
35 | .db()
36 | .collection(defaultCollections.Sessions)
37 | .findOne({ sessionToken })
38 | if (!session) return null
39 | return format.from(session)
40 | },
41 | async verificationToken(identifier_token) {
42 | const token = await client
43 | .db()
44 | .collection(defaultCollections.VerificationTokens)
45 | .findOne(identifier_token)
46 | if (!token) return null
47 | const { _id, ...rest } = token
48 | return rest
49 | },
50 | },
51 | })
52 |
--------------------------------------------------------------------------------
/packages/mongodb/tests/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | CONTAINER_NAME=next-auth-mongodb-test
4 |
5 | JEST_WATCH=false
6 |
7 | # Is the watch flag passed to the script?
8 | while getopts w flag
9 | do
10 | case "${flag}" in
11 | w) JEST_WATCH=true;;
12 | *) continue;;
13 | esac
14 | done
15 |
16 | # Start db
17 | docker run -d --rm -p 27017:27017 --name ${CONTAINER_NAME} mongo
18 |
19 | echo "Waiting 3 sec for db to start..."
20 | sleep 3
21 |
22 | if $JEST_WATCH; then
23 | # Run jest in watch mode
24 | npx jest tests --watch
25 | # Only stop the container after jest has been quit
26 | docker stop "${CONTAINER_NAME}"
27 | else
28 | # Always stop container, but exit with 1 when tests are failing
29 | if npx jest;then
30 | docker stop ${CONTAINER_NAME}
31 | else
32 | docker stop ${CONTAINER_NAME} && exit 1
33 | fi
34 | fi
--------------------------------------------------------------------------------
/packages/mongodb/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "src",
5 | "outDir": "dist"
6 | },
7 | "exclude": ["tests", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/neo4j/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [1.0.2](https://github.com/nextauthjs/adapters/compare/@next-auth/neo4j-adapter@1.0.1...@next-auth/neo4j-adapter@1.0.2) (2021-12-23)
7 |
8 | ### Bug Fixes
9 |
10 | - **neo4j:** update user bugfix ([#352](https://github.com/nextauthjs/adapters/issues/352)) ([8c4ddbd](https://github.com/nextauthjs/adapters/commit/8c4ddbd70d04520a073354870e59040103e3d58d))
11 |
12 | ## [1.0.1](https://github.com/nextauthjs/adapters/compare/@next-auth/neo4j-adapter@1.0.0...@next-auth/neo4j-adapter@1.0.1) (2021-12-06)
13 |
14 | **Note:** Version bump only for package @next-auth/neo4j-adapter
15 |
--------------------------------------------------------------------------------
/packages/neo4j/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Neo4j Adapter - NextAuth.js
5 |
6 | Open Source. Full Stack. Own Your Data.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | ## Overview
16 |
17 | This is the Neo4j Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
18 |
19 | You can find the Neo4j schema in the docs at [next-auth.js.org/adapters/neo4j](next-auth.js.org/adapters/neo4j).
20 |
21 | ## Getting Started
22 |
23 | 1. Install `neo4j-driver`, `next-auth` and `@next-auth/neo4j-adapter`
24 |
25 | ```js
26 | npm install neo4j-driver next-auth @next-auth/neo4j-adapter@next
27 | ```
28 |
29 | 2. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
30 |
31 | ```js
32 | import NextAuth from "next-auth"
33 | import neo4j from "neo4j-driver"
34 | import { Neo4jAdapter } from "@next-auth/neo4j-adapter"
35 |
36 | // Setup your neo4j driver instance
37 | const driver = neo4j.driver(
38 | "bolt://localhost",
39 | neo4j.auth.basic("neo4j", "password")
40 | )
41 | const neo4jSession = driver.session()
42 |
43 | export default NextAuth({
44 | // https://next-auth.js.org/configuration/providers
45 | providers: [],
46 | adapter: Neo4jAdapter(neo4jSession),
47 | ...
48 | })
49 | ```
50 |
51 | ## Contributing
52 |
53 | We're open to all community contributions! If you'd like to contribute in any way, please first read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/canary/CONTRIBUTING.md).
54 |
55 | ## License
56 |
57 | ISC
58 |
--------------------------------------------------------------------------------
/packages/neo4j/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("../../jest.config")
2 |
--------------------------------------------------------------------------------
/packages/neo4j/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/neo4j/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@next-auth/neo4j-adapter",
3 | "version": "1.0.2",
4 | "description": "neo4j adapter for next-auth.",
5 | "homepage": "https://next-auth.js.org",
6 | "repository": "https://github.com/nextauthjs/adapters",
7 | "bugs": {
8 | "url": "https://github.com/nextauthjs/next-auth/issues"
9 | },
10 | "author": "Davey Brown",
11 | "contributors": [
12 | "Balázs Orbán "
13 | ],
14 | "main": "dist/index.js",
15 | "license": "ISC",
16 | "keywords": [
17 | "next-auth",
18 | "next.js",
19 | "oauth",
20 | "neo4j"
21 | ],
22 | "private": false,
23 | "publishConfig": {
24 | "access": "public"
25 | },
26 | "scripts": {
27 | "test:watch": "./tests/test.sh -w",
28 | "test": "./tests/test.sh",
29 | "build": "tsc"
30 | },
31 | "files": [
32 | "README.md",
33 | "dist"
34 | ],
35 | "peerDependencies": {
36 | "neo4j-driver": "^4.0.0",
37 | "next-auth": "^4.0.1"
38 | },
39 | "devDependencies": {
40 | "@types/uuid": "^8.3.3",
41 | "neo4j-driver": "^4.4.0"
42 | },
43 | "dependencies": {
44 | "uuid": "^8.3.2"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/packages/neo4j/src/utils.ts:
--------------------------------------------------------------------------------
1 | import type { Session } from "neo4j-driver"
2 | import { isInt, integer } from "neo4j-driver"
3 |
4 | // https://github.com/honeinc/is-iso-date/blob/master/index.js
5 | const isoDateRE =
6 | /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/
7 |
8 | function isDate(value: any) {
9 | return value && isoDateRE.test(value) && !isNaN(Date.parse(value))
10 | }
11 |
12 | export const format = {
13 | /** Takes a plain old JavaScript object and turns it into a Neo4j compatible object */
14 | to(object: Record) {
15 | const newObject: Record = {}
16 | for (const key in object) {
17 | const value = object[key]
18 | if (value instanceof Date) newObject[key] = value.toISOString()
19 | else newObject[key] = value
20 | }
21 | return newObject
22 | },
23 | /** Takes a Neo4j object and returns a plain old JavaScript object */
24 | from>(object?: Record): T | null {
25 | const newObject: Record = {}
26 | if (!object) return null
27 | for (const key in object) {
28 | const value = object[key]
29 | if (isDate(value)) {
30 | newObject[key] = new Date(value)
31 | } else if (isInt(value)) {
32 | if (integer.inSafeRange(value)) newObject[key] = value.toNumber()
33 | else newObject[key] = value.toString()
34 | } else {
35 | newObject[key] = value
36 | }
37 | }
38 |
39 | return newObject as T
40 | },
41 | }
42 |
43 | export function client(session: Session) {
44 | return {
45 | /** Reads values from the database */
46 | async read(statement: string, values?: any): Promise {
47 | const result = await session.readTransaction((tx) =>
48 | tx.run(statement, values)
49 | )
50 |
51 | return format.from(result?.records[0]?.get(0)) ?? null
52 | },
53 | /**
54 | * Reads/writes values from/to the database.
55 | * Properties are available under `$data`
56 | */
57 | async write(statement: string, values: T): Promise {
58 | const result = await session.writeTransaction((tx) =>
59 | tx.run(statement, { data: format.to(values) })
60 | )
61 |
62 | return format.from(result?.records[0]?.toObject())
63 | },
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/packages/neo4j/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | import * as neo4j from "neo4j-driver"
2 | import { runBasicTests } from "../../../basic-tests"
3 | import statements from "./resources/statements"
4 |
5 | import { Neo4jAdapter, format } from "../src"
6 |
7 | const driver = neo4j.driver(
8 | "bolt://localhost",
9 | neo4j.auth.basic("neo4j", "password")
10 | )
11 |
12 | const neo4jSession = driver.session()
13 |
14 | runBasicTests({
15 | adapter: Neo4jAdapter(neo4jSession),
16 | db: {
17 | async connect() {
18 | for await (const statement of statements.split(";")) {
19 | if (!statement.length) return
20 | await neo4jSession.writeTransaction((tx) => tx.run(statement))
21 | }
22 | },
23 | async disconnect() {
24 | await neo4jSession.writeTransaction((tx) =>
25 | tx.run(
26 | `MATCH (n)
27 | DETACH DELETE n
28 | RETURN count(n)`
29 | )
30 | )
31 | await neo4jSession.close()
32 | await driver.close()
33 | },
34 | async user(id) {
35 | const result = await neo4jSession.readTransaction((tx) =>
36 | tx.run(`MATCH (u:User) RETURN u`, { id })
37 | )
38 | return format.from(result?.records[0]?.get("u")?.properties)
39 | },
40 |
41 | async session(sessionToken: any) {
42 | const result = await neo4jSession.readTransaction((tx) =>
43 | tx.run(
44 | `MATCH (u:User)-[:HAS_SESSION]->(s:Session)
45 | RETURN s, u.id AS userId`,
46 | { sessionToken }
47 | )
48 | )
49 | const session = result?.records[0]?.get("s")?.properties
50 | const userId = result?.records[0]?.get("userId")
51 |
52 | if (!session || session.userId || !userId) return null
53 |
54 | return { ...format.from(session), userId }
55 | },
56 |
57 | async account(provider_providerAccountId) {
58 | const result = await neo4jSession.readTransaction((tx) =>
59 | tx.run(
60 | `MATCH (u:User)-[:HAS_ACCOUNT]->(a:Account)
61 | RETURN a, u.id AS userId`,
62 | provider_providerAccountId
63 | )
64 | )
65 |
66 | const account = result?.records[0]?.get("a")?.properties
67 | const userId = result?.records[0]?.get("userId")
68 |
69 | if (!account || account.userId || !userId) return null
70 |
71 | return { ...format.from(account), userId }
72 | },
73 |
74 | async verificationToken(identifier_token) {
75 | const result = await neo4jSession.readTransaction((tx) =>
76 | tx.run(
77 | `MATCH (v:VerificationToken)
78 | RETURN v`,
79 | identifier_token
80 | )
81 | )
82 |
83 | return format.from(result?.records[0]?.get("v")?.properties)
84 | },
85 | },
86 | })
87 |
--------------------------------------------------------------------------------
/packages/neo4j/tests/resources/statements.ts:
--------------------------------------------------------------------------------
1 | // Constraints and indexes - relevant to Neo4j Community Edition.
2 | export default `
3 | CREATE CONSTRAINT user_id_constraint IF NOT EXISTS
4 | ON (u:User) ASSERT u.id IS UNIQUE;
5 |
6 | CREATE INDEX user_id_index IF NOT EXISTS
7 | FOR (u:User) ON (u.id);
8 |
9 | CREATE INDEX user_email_index IF NOT EXISTS
10 | FOR (u:User) ON (u.email);
11 |
12 | CREATE CONSTRAINT session_session_token_constraint IF NOT EXISTS
13 | ON (s:Session) ASSERT s.sessionToken IS UNIQUE;
14 |
15 | CREATE INDEX session_session_token_index IF NOT EXISTS
16 | FOR (s:Session) ON (s.sessionToken);
17 |
18 | CREATE INDEX account_provider_index IF NOT EXISTS
19 | FOR (a:Account) ON (a.provider);
20 |
21 | CREATE INDEX account_provider_account_id_index IF NOT EXISTS
22 | FOR (a:Account) ON (a.providerAccountId);
23 |
24 | CREATE INDEX verification_token_identifier_index IF NOT EXISTS
25 | FOR (v:VerificationToken) ON (v.identifier);
26 |
27 | CREATE INDEX verification_token_token_index IF NOT EXISTS
28 | FOR (v:VerificationToken) ON (v.token);`
29 |
--------------------------------------------------------------------------------
/packages/neo4j/tests/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
4 | NEO4J_USER=neo4j
5 | NEO4J_PASS=password
6 | CONTAINER_NAME=next-auth-neo4j-test-e
7 | JEST_WATCH=false
8 |
9 | # Is the watch flag passed to the script?
10 | while getopts w flag
11 | do
12 | case "${flag}" in
13 | w) JEST_WATCH=true;;
14 | *) continue;;
15 | esac
16 | done
17 |
18 | # Start db
19 | docker run -d --rm \
20 | -e NEO4J_AUTH=${NEO4J_USER}/${NEO4J_PASS} \
21 | -e TEST_NEO4J_USER=${NEO4J_USER} \
22 | -e TEST_NEO4J_PASS=${NEO4J_PASS} \
23 | --name "${CONTAINER_NAME}" \
24 | -p7474:7474 -p7687:7687 \
25 | neo4j:4.2.0
26 |
27 | # For debug or testing it may be useful to use neo4j enterprise edition.
28 | # Use the lines below in the docker run statement.
29 | # -e NEO4J_ACCEPT_LICENSE_AGREEMENT=yes \
30 | # neo4j:4.2.0-enterprise
31 |
32 | echo "Waiting 5 sec for db to start..." && sleep 5
33 |
34 | if $JEST_WATCH; then
35 | # Run jest in watch mode
36 | npx jest tests --watch
37 | # Only stop the container after jest has been quit
38 | docker stop "${CONTAINER_NAME}"
39 | else
40 | # Always stop container, but exit with 1 when tests are failing
41 | if npx jest tests --detectOpenHandles --forceExit;then
42 | docker stop "${CONTAINER_NAME}"
43 | else
44 | docker stop "${CONTAINER_NAME}" && exit 1
45 | fi
46 | fi
47 |
--------------------------------------------------------------------------------
/packages/neo4j/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "src",
5 | "outDir": "dist"
6 | },
7 | "exclude": ["tests", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/pouchdb/.gitignore:
--------------------------------------------------------------------------------
1 | .pouchdb
--------------------------------------------------------------------------------
/packages/pouchdb/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [0.1.3](https://github.com/nextauthjs/adapters/compare/@next-auth/pouchdb-adapter@0.1.2...@next-auth/pouchdb-adapter@0.1.3) (2021-08-17)
7 |
8 | **Note:** Version bump only for package @next-auth/pouchdb-adapter
9 |
10 | ## [0.1.2](https://github.com/nextauthjs/adapters/compare/@next-auth/pouchdb-adapter@0.1.1...@next-auth/pouchdb-adapter@0.1.2) (2021-07-02)
11 |
12 | **Note:** Version bump only for package @next-auth/pouchdb-adapter
13 |
14 | ## [0.1.1](https://github.com/nextauthjs/adapters/compare/@next-auth/pouchdb-adapter@0.1.0...@next-auth/pouchdb-adapter@0.1.1) (2021-06-30)
15 |
16 | **Note:** Version bump only for package @next-auth/pouchdb-adapter
17 |
--------------------------------------------------------------------------------
/packages/pouchdb/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
PouchDB Adapter - NextAuth.js
5 |
6 | Open Source. Full Stack. Own Your Data.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | ## Overview
16 |
17 | This is the PouchDB Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
18 |
19 | Depending on your architecture you can use PouchDB's http adapter to reach any database compliant with the CouchDB protocol (CouchDB, Cloudant, ...) or use any other PouchDB compatible adapter (leveldb, in-memory, ...)
20 |
21 | ## Getting Started
22 |
23 | 1. Install `next-auth` and `@next-auth/pouchdb-adapter`, as well as `pouchdb`.
24 |
25 | > **Prerequesite**: Your PouchDB instance MUST provide the `pouchdb-find` plugin since it is used internally by the adapter to build and manage indexes
26 |
27 | ```js
28 | npm install next-auth @next-auth/pouchdb-adapter pouchdb
29 | ```
30 |
31 | 2. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
32 |
33 | ```js
34 | import NextAuth from "next-auth"
35 | import Providers from "next-auth/providers"
36 | import { PouchDBAdapter } from "@next-auth/pouchdb-adapter"
37 | import PouchDB from "pouchdb"
38 |
39 | // Setup your PouchDB instance and database
40 | PouchDB.plugin(require("pouchdb-adapter-leveldb")) // Or any other PouchDB-compliant adapter
41 | .plugin(require("pouchdb-find")) // Don't forget the `pouchdb-find` plugin
42 |
43 | const pouchdb = new PouchDB("auth_db", { adapter: "leveldb" })
44 |
45 | // For more information on each option (and a full list of options) go to
46 | // https://next-auth.js.org/configuration/options
47 | export default NextAuth({
48 | // https://next-auth.js.org/configuration/providers
49 | providers: [
50 | Providers.Google({
51 | clientId: process.env.GOOGLE_ID,
52 | clientSecret: process.env.GOOGLE_SECRET,
53 | }),
54 | ],
55 | adapter: PouchDBAdapter(pouchdb),
56 | // ...
57 | })
58 | ```
59 |
60 | ## Advanced
61 |
62 | ### Memory-First Caching Strategy
63 |
64 | If you need to boost your authentication layer performance, you may use PouchDB's powerful sync features and various adapters, to build a memory-first caching strategy.
65 |
66 | Use an in-memory PouchDB as your main authentication database, and synchronize it with any other persisted PouchDB. You may do a one way, one-off replication at startup from the persisted PouchDB into the in-memory PouchDB, then two-way, continuous, retriable sync.
67 |
68 | This will probably not improve performance much in a serverless environment for various reasons such as concurrency, function startup time increases, etc.
69 |
70 | For more details, please see https://pouchdb.com/api.html#sync
71 |
72 | ## Contributing
73 |
74 | We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
75 |
76 | ## License
77 |
78 | ISC
79 |
--------------------------------------------------------------------------------
/packages/pouchdb/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("../../jest.config")
2 |
--------------------------------------------------------------------------------
/packages/pouchdb/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
17 |
--------------------------------------------------------------------------------
/packages/pouchdb/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@next-auth/pouchdb-adapter",
3 | "version": "0.1.3",
4 | "description": "PouchDB adapter for next-auth.",
5 | "homepage": "https://next-auth.js.org",
6 | "repository": "https://github.com/nextauthjs/adapters",
7 | "bugs": {
8 | "url": "https://github.com/nextauthjs/next-auth/issues"
9 | },
10 | "author": "jpbourgeon (https://github.com/jpbourgeon)",
11 | "main": "dist/index.js",
12 | "license": "ISC",
13 | "keywords": [
14 | "next-auth",
15 | "next.js",
16 | "oauth",
17 | "pouchdb"
18 | ],
19 | "private": false,
20 | "publishConfig": {
21 | "access": "public"
22 | },
23 | "scripts": {
24 | "build": "tsc",
25 | "tdd": "jest --watch",
26 | "test": "jest"
27 | },
28 | "files": [
29 | "README.md",
30 | "dist"
31 | ],
32 | "peerDependencies": {
33 | "next-auth": "^3.23.3",
34 | "pouchdb": "^7.2.2",
35 | "pouchdb-find": "^7.2.2"
36 | },
37 | "dependencies": {
38 | "crypto": "^1.0.1",
39 | "ulid": "^2.3.0"
40 | },
41 | "devDependencies": {
42 | "@types/pouchdb": "^6.4.0",
43 | "pouchdb": "^7.2.2",
44 | "pouchdb-adapter-memory": "^7.2.2",
45 | "pouchdb-find": "^7.2.2"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/packages/pouchdb/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "src",
5 | "outDir": "dist",
6 | "allowSyntheticDefaultImports": true
7 | },
8 | "exclude": ["tests", "dist"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/prisma/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [1.0.1](https://github.com/nextauthjs/adapters/compare/@next-auth/prisma-adapter@1.0.0...@next-auth/prisma-adapter@1.0.1) (2021-12-06)
7 |
8 | **Note:** Version bump only for package @next-auth/prisma-adapter
9 |
10 | ## [0.5.4](https://github.com/nextauthjs/adapters/compare/@next-auth/prisma-adapter@0.5.3...@next-auth/prisma-adapter@0.5.4) (2021-08-17)
11 |
12 | **Note:** Version bump only for package @next-auth/prisma-adapter
13 |
14 | ## [0.5.3](https://github.com/nextauthjs/adapters/compare/@next-auth/prisma-adapter@0.5.2...@next-auth/prisma-adapter@0.5.3) (2021-07-11)
15 |
16 | ### Bug Fixes
17 |
18 | - **prisma:** remove spread profile object ([#166](https://github.com/nextauthjs/adapters/issues/166)) ([d33dfb0](https://github.com/nextauthjs/adapters/commit/d33dfb0ea20667004831e5ac41e718008f233025))
19 |
20 | ## [0.5.2](https://github.com/nextauthjs/adapters/compare/@next-auth/prisma-adapter@0.5.1...@next-auth/prisma-adapter@0.5.2) (2021-07-02)
21 |
22 | **Note:** Version bump only for package @next-auth/prisma-adapter
23 |
24 | ## [0.5.1](https://github.com/nextauthjs/adapters/compare/@next-auth/prisma-adapter@0.5.0...@next-auth/prisma-adapter@0.5.1) (2021-06-30)
25 |
26 | **Note:** Version bump only for package @next-auth/prisma-adapter
27 |
--------------------------------------------------------------------------------
/packages/prisma/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Prisma Adapter - NextAuth.js
5 |
6 | Open Source. Full Stack. Own Your Data.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | ## Overview
16 |
17 | This is the Prisma Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
18 |
19 | You can find the Prisma schema in the docs at [next-auth.js.org/adapters/prisma](https://next-auth.js.org/adapters/prisma).
20 |
21 | ## Getting Started
22 |
23 | 1. Install `next-auth` and `@next-auth/prisma-adapter` as well as `prisma` and `@prisma/client`.
24 |
25 | ```js
26 | npm install next-auth @next-auth/prisma-adapter @prisma/client
27 | npm install --save-dev prisma
28 | ```
29 |
30 | 2. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
31 |
32 | ```js
33 | import NextAuth from "next-auth"
34 | import { PrismaAdapter } from "@next-auth/prisma-adapter"
35 | import * as Prisma from "@prisma/client"
36 |
37 | const prisma = new Prisma.PrismaClient()
38 |
39 | // For more information on each option (and a full list of options) go to
40 | // https://next-auth.js.org/configuration/options
41 | export default NextAuth({
42 | // https://next-auth.js.org/configuration/providers
43 | providers: [],
44 | adapter: PrismaAdapter(prisma)
45 | ...
46 | })
47 | ```
48 |
49 | ## Contributing
50 |
51 | We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
52 |
53 | ## License
54 |
55 | ISC
56 |
--------------------------------------------------------------------------------
/packages/prisma/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("../../jest.config")
2 |
--------------------------------------------------------------------------------
/packages/prisma/logo.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/prisma/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@next-auth/prisma-adapter",
3 | "version": "1.0.1",
4 | "description": "Prisma adapter for next-auth.",
5 | "homepage": "https://next-auth.js.org",
6 | "repository": "https://github.com/nextauthjs/adapters",
7 | "bugs": {
8 | "url": "https://github.com/nextauthjs/next-auth/issues"
9 | },
10 | "author": "William Luke",
11 | "main": "dist/index.js",
12 | "license": "ISC",
13 | "keywords": [
14 | "next-auth",
15 | "next.js",
16 | "oauth",
17 | "prisma"
18 | ],
19 | "private": false,
20 | "publishConfig": {
21 | "access": "public"
22 | },
23 | "scripts": {
24 | "clean": "rm -rf ./prisma/migrations && rm ./prisma/dev.db*",
25 | "init:default": "prisma migrate dev --name init --skip-seed",
26 | "init:custom": "prisma migrate dev --name init-custom --schema ./prisma/custom.prisma",
27 | "test:default": "yarn init:default && jest",
28 | "test:custom": "yarn init:custom && CUSTOM_MODEL=1 jest",
29 | "test": "yarn test:default && yarn test:custom",
30 | "build": "prisma generate && tsc",
31 | "studio": "prisma studio"
32 | },
33 | "files": [
34 | "README.md",
35 | "dist"
36 | ],
37 | "peerDependencies": {
38 | "@prisma/client": ">=2.26.0 || >=3",
39 | "next-auth": "^4.0.1"
40 | },
41 | "devDependencies": {
42 | "@prisma/client": "^3.0.2",
43 | "prisma": "^3.0.2"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/packages/prisma/prisma/custom.prisma:
--------------------------------------------------------------------------------
1 | datasource db {
2 | provider = "sqlite"
3 | url = "file:./dev.db"
4 | }
5 |
6 | generator client {
7 | provider = "prisma-client-js"
8 | }
9 |
10 | model User {
11 | id String @id @default(cuid())
12 | name String?
13 | email String? @unique
14 | emailVerified DateTime?
15 | image String?
16 | phone String?
17 | role String?
18 | accounts Account[]
19 | sessions Session[]
20 | }
21 |
22 | model Account {
23 | id String @id @default(cuid())
24 | userId String
25 | type String
26 | provider String
27 | providerAccountId String
28 | refresh_token String?
29 | access_token String?
30 | expires_at Int?
31 | token_type String?
32 | scope String?
33 | id_token String?
34 | session_state String?
35 |
36 | user User @relation(fields: [userId], references: [id], onDelete: Cascade)
37 |
38 | @@unique([provider, providerAccountId])
39 | }
40 |
41 | model Session {
42 | id String @id @default(cuid())
43 | sessionToken String @unique
44 | userId String
45 | expires DateTime
46 | user User @relation(fields: [userId], references: [id], onDelete: Cascade)
47 | }
48 |
49 | model VerificationToken {
50 | identifier String
51 | token String @unique
52 | expires DateTime
53 |
54 | @@unique([identifier, token])
55 | }
56 |
--------------------------------------------------------------------------------
/packages/prisma/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (i.e. Git)
3 | provider = "sqlite"
--------------------------------------------------------------------------------
/packages/prisma/prisma/schema.prisma:
--------------------------------------------------------------------------------
1 | datasource db {
2 | provider = "sqlite"
3 | url = "file:./dev.db"
4 | }
5 |
6 | generator client {
7 | provider = "prisma-client-js"
8 | }
9 |
10 | model User {
11 | id String @id @default(cuid())
12 | name String?
13 | email String? @unique
14 | emailVerified DateTime?
15 | image String?
16 | accounts Account[]
17 | sessions Session[]
18 | }
19 |
20 | model Account {
21 | id String @id @default(cuid())
22 | userId String
23 | type String
24 | provider String
25 | providerAccountId String
26 | refresh_token String?
27 | access_token String?
28 | expires_at Int?
29 | token_type String?
30 | scope String?
31 | id_token String?
32 | session_state String?
33 |
34 | user User @relation(fields: [userId], references: [id], onDelete: Cascade)
35 |
36 | @@unique([provider, providerAccountId])
37 | }
38 |
39 | model Session {
40 | id String @id @default(cuid())
41 | sessionToken String @unique
42 | userId String
43 | expires DateTime
44 | user User @relation(fields: [userId], references: [id], onDelete: Cascade)
45 | }
46 |
47 | model VerificationToken {
48 | identifier String
49 | token String @unique
50 | expires DateTime
51 |
52 | @@unique([identifier, token])
53 | }
54 |
--------------------------------------------------------------------------------
/packages/prisma/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { PrismaClient, Prisma } from "@prisma/client"
2 | import type { Adapter } from "next-auth/adapters"
3 |
4 | export function PrismaAdapter(p: PrismaClient): Adapter {
5 | return {
6 | createUser: (data) => p.user.create({ data }),
7 | getUser: (id) => p.user.findUnique({ where: { id } }),
8 | getUserByEmail: (email) => p.user.findUnique({ where: { email } }),
9 | async getUserByAccount(provider_providerAccountId) {
10 | const account = await p.account.findUnique({
11 | where: { provider_providerAccountId },
12 | select: { user: true },
13 | })
14 | return account?.user ?? null
15 | },
16 | updateUser: (data) => p.user.update({ where: { id: data.id }, data }),
17 | deleteUser: (id) => p.user.delete({ where: { id } }),
18 | linkAccount: (data) => p.account.create({ data }) as any,
19 | unlinkAccount: (provider_providerAccountId) =>
20 | p.account.delete({ where: { provider_providerAccountId } }) as any,
21 | async getSessionAndUser(sessionToken) {
22 | const userAndSession = await p.session.findUnique({
23 | where: { sessionToken },
24 | include: { user: true },
25 | })
26 | if (!userAndSession) return null
27 | const { user, ...session } = userAndSession
28 | return { user, session }
29 | },
30 | createSession: (data) => p.session.create({ data }),
31 | updateSession: (data) =>
32 | p.session.update({ data, where: { sessionToken: data.sessionToken } }),
33 | deleteSession: (sessionToken) =>
34 | p.session.delete({ where: { sessionToken } }),
35 | createVerificationToken: (data) => p.verificationToken.create({ data }),
36 | async useVerificationToken(identifier_token) {
37 | try {
38 | return await p.verificationToken.delete({ where: { identifier_token } })
39 | } catch (error) {
40 | // If token already used/deleted, just return null
41 | // https://www.prisma.io/docs/reference/api-reference/error-reference#p2025
42 | if ((error as Prisma.PrismaClientKnownRequestError).code === "P2025")
43 | return null
44 | throw error
45 | }
46 | },
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/packages/prisma/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | import { runBasicTests } from "../../../basic-tests"
2 | import { PrismaClient } from "@prisma/client"
3 | import { PrismaAdapter } from "../src"
4 | const prisma = new PrismaClient()
5 |
6 | runBasicTests({
7 | adapter: PrismaAdapter(prisma),
8 | db: {
9 | connect: async () => {
10 | await Promise.all([
11 | prisma.user.deleteMany({}),
12 | prisma.account.deleteMany({}),
13 | prisma.session.deleteMany({}),
14 | prisma.verificationToken.deleteMany({}),
15 | ])
16 | },
17 | disconnect: async () => {
18 | await Promise.all([
19 | prisma.user.deleteMany({}),
20 | prisma.account.deleteMany({}),
21 | prisma.session.deleteMany({}),
22 | prisma.verificationToken.deleteMany({}),
23 | ])
24 | await prisma.$disconnect()
25 | },
26 | verificationToken: (identifier_token) =>
27 | prisma.verificationToken.findUnique({
28 | where: { identifier_token },
29 | }),
30 | user: (id) => prisma.user.findUnique({ where: { id } }),
31 | account: (provider_providerAccountId) =>
32 | prisma.account.findUnique({
33 | where: { provider_providerAccountId },
34 | }),
35 | session: (sessionToken) =>
36 | prisma.session.findUnique({ where: { sessionToken } }),
37 | },
38 | })
39 |
--------------------------------------------------------------------------------
/packages/prisma/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "src",
5 | "outDir": "dist"
6 | },
7 | "exclude": ["tests", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/sequelize/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [1.0.2](https://github.com/nextauthjs/adapters/compare/@next-auth/sequelize-adapter@1.0.1...@next-auth/sequelize-adapter@1.0.2) (2022-01-23)
7 |
8 | ### Bug Fixes
9 |
10 | - **sequelize:** prevent indexes duplication ([#375](https://github.com/nextauthjs/adapters/issues/375)) ([c6642b5](https://github.com/nextauthjs/adapters/commit/c6642b51955dec382b1bc50722163444d5bfeb2d))
11 |
12 | ## [1.0.1](https://github.com/nextauthjs/adapters/compare/@next-auth/sequelize-adapter@1.0.0...@next-auth/sequelize-adapter@1.0.1) (2021-12-06)
13 |
14 | **Note:** Version bump only for package @next-auth/sequelize-adapter
15 |
--------------------------------------------------------------------------------
/packages/sequelize/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Sequelize Adapter - NextAuth.js
5 |
6 | Open Source. Full Stack. Own Your Data.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | ## Overview
16 |
17 | This is the Sequelize Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
18 |
19 | You can find the Sequelize schema in the docs at [next-auth.js.org/adapters/sequelize](https://next-auth.js.org/adapters/sequelize).
20 |
21 | ## Getting Started
22 |
23 | 1. Install `next-auth` and `@next-auth/sequelize-adapter` as well as `sequelize` and your [database driver](https://sequelize.org/master/manual/getting-started.html) of choice.
24 |
25 | ```js
26 | npm install next-auth @next-auth/sequelize-adapter sequelize sqlite3
27 | npm install --save-dev sequelize
28 | ```
29 |
30 | 2. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
31 |
32 | ```js
33 | import NextAuth from "next-auth"
34 | import SequelizeAdapter from "@next-auth/sequelize-adapter"
35 | import Sequelize from 'sequelize'
36 |
37 | const sequelize = new Sequelize("sqlite::memory:")
38 |
39 | // For more information on each option (and a full list of options) go to
40 | // https://next-auth.js.org/configuration/options
41 | export default NextAuth({
42 | ...
43 | adapter: SequelizeAdapter(sequelize)
44 | ...
45 | })
46 | ```
47 |
48 | ## Updating the database schema
49 |
50 | In development, the sequelize adapter will create the necessary tables, foreign keys and indexes in your database. In production, synchronization is disabled. Best practice is to create the [required tables](https://next-auth.js.org/adapters/models) in your database via [migrations](https://sequelize.org/master/manual/migrations.html).
51 |
52 | In development, if you do not want the adapter to automatically create tables, you are able to pass `{ synchronize: false }` as the second option to `SequelizeAdapter` to disable this behavior:
53 |
54 | ```js
55 | import NextAuth from "next-auth"
56 | import SequelizeAdapter from "@next-auth/sequelize-adapter"
57 | import Sequelize from 'sequelize'
58 |
59 | const sequelize = new Sequelize("sqlite::memory:")
60 |
61 | export default NextAuth({
62 | ...
63 | adapter: SequelizeAdapter(sequelize, { synchronize: false })
64 | ...
65 | })
66 | ```
67 |
68 | ## Using custom models
69 |
70 | Sequelize models are option to customization like so:
71 |
72 | ```js
73 | import NextAuth from "next-auth"
74 | import SequelizeAdapter, { models } from "@next-auth/sequelize-adapter"
75 | import Sequelize, { DataTypes } from 'sequelize'
76 |
77 | const sequelize = new Sequelize("sqlite::memory:")
78 |
79 | export default NextAuth({
80 | ...
81 | adapter: SequelizeAdapter(sequelize, {
82 | models: {
83 | User: sequelize.define('user', { ...models.User, phoneNumber: DataTypes.STRING })
84 | }
85 | })
86 | ...
87 | })
88 | ```
89 |
90 | ## Contributing
91 |
92 | We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
93 |
94 | ## License
95 |
96 | ISC
97 |
--------------------------------------------------------------------------------
/packages/sequelize/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("../../jest.config")
2 |
--------------------------------------------------------------------------------
/packages/sequelize/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/packages/sequelize/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@next-auth/sequelize-adapter",
3 | "version": "1.0.2",
4 | "description": "Sequelize adapter for next-auth.",
5 | "homepage": "https://next-auth.js.org",
6 | "repository": "https://github.com/nextauthjs/adapters",
7 | "bugs": {
8 | "url": "https://github.com/nextauthjs/adapters/issues"
9 | },
10 | "author": "github.com/luke-j",
11 | "main": "dist/index.js",
12 | "license": "ISC",
13 | "keywords": [
14 | "next-auth",
15 | "next.js",
16 | "oauth",
17 | "sequelize"
18 | ],
19 | "private": false,
20 | "publishConfig": {
21 | "access": "public"
22 | },
23 | "scripts": {
24 | "test": "jest",
25 | "build": "tsc"
26 | },
27 | "files": [
28 | "README.md",
29 | "dist"
30 | ],
31 | "peerDependencies": {
32 | "next-auth": "^4.0.1",
33 | "sequelize": "^6.6.5"
34 | },
35 | "devDependencies": {
36 | "sequelize": "^6.6.5"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/packages/sequelize/src/models.ts:
--------------------------------------------------------------------------------
1 | import { DataTypes } from "sequelize"
2 |
3 | export const Account = {
4 | id: {
5 | type: DataTypes.UUID,
6 | defaultValue: DataTypes.UUIDV4,
7 | primaryKey: true,
8 | },
9 | type: { type: DataTypes.STRING, allowNull: false },
10 | provider: { type: DataTypes.STRING, allowNull: false },
11 | providerAccountId: { type: DataTypes.STRING, allowNull: false },
12 | refresh_token: { type: DataTypes.STRING },
13 | access_token: { type: DataTypes.STRING },
14 | expires_at: { type: DataTypes.INTEGER },
15 | token_type: { type: DataTypes.STRING },
16 | scope: { type: DataTypes.STRING },
17 | id_token: { type: DataTypes.STRING },
18 | session_state: { type: DataTypes.STRING },
19 | userId: { type: DataTypes.UUID },
20 | }
21 |
22 | export const User = {
23 | id: {
24 | type: DataTypes.UUID,
25 | defaultValue: DataTypes.UUIDV4,
26 | primaryKey: true,
27 | },
28 | name: { type: DataTypes.STRING },
29 | email: { type: DataTypes.STRING, unique: 'email' },
30 | emailVerified: { type: DataTypes.DATE },
31 | image: { type: DataTypes.STRING },
32 | }
33 |
34 | export const Session = {
35 | id: {
36 | type: DataTypes.UUID,
37 | defaultValue: DataTypes.UUIDV4,
38 | primaryKey: true,
39 | },
40 | expires: { type: DataTypes.DATE, allowNull: false },
41 | sessionToken: { type: DataTypes.STRING, unique: 'sessionToken', allowNull: false },
42 | userId: { type: DataTypes.UUID },
43 | }
44 |
45 | export const VerificationToken = {
46 | token: { type: DataTypes.STRING, primaryKey: true },
47 | identifier: { type: DataTypes.STRING, allowNull: false },
48 | expires: { type: DataTypes.DATE, allowNull: false },
49 | }
50 |
--------------------------------------------------------------------------------
/packages/sequelize/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "src",
5 | "outDir": "dist"
6 | },
7 | "exclude": ["tests", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/.dockerignore:
--------------------------------------------------------------------------------
1 | # Exclude directories we don't need from Docker context to improve build time
2 | node_modules
3 | www
4 | src
--------------------------------------------------------------------------------
/packages/typeorm-legacy/.gitignore:
--------------------------------------------------------------------------------
1 | # Misc
2 | .DS_Store
3 |
4 | .env
5 | .env.local
6 | .env.development.local
7 | .env.test.local
8 | .env.production.local
9 |
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Dependencies
15 | node_modules
16 |
17 | # Build dirs
18 | .next
19 | /build
20 | /dist
21 | /www/build
22 |
23 | # Generated files
24 | .docusaurus
25 | .cache-loader
26 | .next
27 |
28 | # VS
29 | /.vs/slnx.sqlite-journal
30 | /.vs/slnx.sqlite
31 | /.vs
32 | .vscode
33 |
34 | # GitHub Actions runner
35 | /actions-runner
36 | /_work
--------------------------------------------------------------------------------
/packages/typeorm-legacy/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [1.0.1](https://github.com/nextauthjs/adapters/compare/@next-auth/typeorm-legacy-adapter@1.0.0...@next-auth/typeorm-legacy-adapter@1.0.1) (2021-12-06)
7 |
8 | **Note:** Version bump only for package @next-auth/typeorm-legacy-adapter
9 |
10 | ## [0.1.4](https://github.com/nextauthjs/adapters/compare/@next-auth/typeorm-legacy-adapter@0.1.3...@next-auth/typeorm-legacy-adapter@0.1.4) (2021-08-17)
11 |
12 | **Note:** Version bump only for package @next-auth/typeorm-legacy-adapter
13 |
14 | ## [0.1.3](https://github.com/nextauthjs/adapters/compare/@next-auth/typeorm-legacy-adapter@0.1.2...@next-auth/typeorm-legacy-adapter@0.1.3) (2021-07-11)
15 |
16 | **Note:** Version bump only for package @next-auth/typeorm-legacy-adapter
17 |
18 | ## [0.1.2](https://github.com/nextauthjs/adapters/compare/@next-auth/typeorm-legacy-adapter@0.1.1...@next-auth/typeorm-legacy-adapter@0.1.2) (2021-07-02)
19 |
20 | **Note:** Version bump only for package @next-auth/typeorm-legacy-adapter
21 |
22 | ## [0.1.1](https://github.com/nextauthjs/adapters/compare/@next-auth/typeorm-legacy-adapter@0.1.0...@next-auth/typeorm-legacy-adapter@0.1.1) (2021-06-30)
23 |
24 | **Note:** Version bump only for package @next-auth/typeorm-legacy-adapter
25 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("../../jest.config")
2 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nextauthjs/adapters/1237a5372004951eccb37c5f7481e5fcb62415b6/packages/typeorm-legacy/logo.png
--------------------------------------------------------------------------------
/packages/typeorm-legacy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@next-auth/typeorm-legacy-adapter",
3 | "version": "1.0.1",
4 | "description": "TypeORM (legacy) adapter for next-auth.",
5 | "homepage": "https://next-auth.js.org",
6 | "repository": "https://github.com/nextauthjs/adapters",
7 | "bugs": {
8 | "url": "https://github.com/nextauthjs/adapters/issues"
9 | },
10 | "author": "Iain Collins",
11 | "contributors": [
12 | "Balázs Orbán "
13 | ],
14 | "main": "dist/index.js",
15 | "files": [
16 | "README.md",
17 | "dist"
18 | ],
19 | "license": "ISC",
20 | "keywords": [
21 | "next-auth",
22 | "next.js",
23 | "oauth",
24 | "typeorm"
25 | ],
26 | "private": false,
27 | "publishConfig": {
28 | "access": "public"
29 | },
30 | "scripts": {
31 | "build": "tsc",
32 | "init:db": "tests/init.sh",
33 | "test:containers": "tests/test.sh",
34 | "test": "tests/test.sh",
35 | "mysql": "yarn init:db && tests/mysql/test.sh",
36 | "postgres": "yarn init:db && tests/postgresql/test.sh",
37 | "sqlite": "tests/sqlite/test.sh"
38 | },
39 | "devDependencies": {
40 | "mssql": "^7.2.1",
41 | "mysql": "^2.18.1",
42 | "pg": "^8.7.1",
43 | "sqlite3": "^5.0.2",
44 | "typeorm": "^0.2.37",
45 | "typeorm-naming-strategies": "^2.0.0"
46 | },
47 | "peerDependencies": {
48 | "mssql": "^6.2.1 || 7",
49 | "mysql": "^2.18.1",
50 | "next-auth": "^4.0.1",
51 | "pg": "^8.2.1",
52 | "sqlite3": "^5.0.2",
53 | "typeorm": "^0.2.31"
54 | },
55 | "peerDependenciesMeta": {
56 | "mysql": {
57 | "optional": true
58 | },
59 | "mssql": {
60 | "optional": true
61 | },
62 | "pg": {
63 | "optional": true
64 | },
65 | "sqlite3": {
66 | "optional": true
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/src/entities.ts:
--------------------------------------------------------------------------------
1 | import type { ValueTransformer } from "typeorm"
2 | import {
3 | Entity,
4 | PrimaryGeneratedColumn,
5 | Column,
6 | ManyToOne,
7 | OneToMany,
8 | } from "typeorm"
9 |
10 | const transformer: Record<"date" | "bigint", ValueTransformer> = {
11 | date: {
12 | from: (date: string | null) => date && new Date(parseInt(date, 10)),
13 | to: (date?: Date) => date?.valueOf().toString(),
14 | },
15 | bigint: {
16 | from: (bigInt: string | null) => bigInt && parseInt(bigInt, 10),
17 | to: (bigInt?: number) => bigInt?.toString(),
18 | },
19 | }
20 |
21 | @Entity({ name: "users" })
22 | export class UserEntity {
23 | @PrimaryGeneratedColumn("uuid")
24 | id!: string
25 |
26 | @Column({ type: "varchar", nullable: true })
27 | name!: string | null
28 |
29 | @Column({ type: "varchar", nullable: true, unique: true })
30 | email!: string | null
31 |
32 | @Column({ type: "varchar", nullable: true, transformer: transformer.date })
33 | emailVerified!: string | null
34 |
35 | @Column({ type: "varchar", nullable: true })
36 | image!: string | null
37 |
38 | @OneToMany(() => SessionEntity, (session) => session.userId)
39 | sessions!: SessionEntity[]
40 |
41 | @OneToMany(() => AccountEntity, (account) => account.userId)
42 | accounts!: AccountEntity[]
43 | }
44 |
45 | @Entity({ name: "accounts" })
46 | export class AccountEntity {
47 | @PrimaryGeneratedColumn("uuid")
48 | id!: string
49 |
50 | @Column({ type: "uuid" })
51 | userId!: string
52 |
53 | @Column()
54 | type!: string
55 |
56 | @Column()
57 | provider!: string
58 |
59 | @Column()
60 | providerAccountId!: string
61 |
62 | @Column({ type: "varchar", nullable: true })
63 | refresh_token!: string
64 |
65 | @Column({ type: "varchar", nullable: true })
66 | access_token!: string | null
67 |
68 | @Column({
69 | nullable: true,
70 | type: "bigint",
71 | transformer: transformer.bigint,
72 | })
73 | expires_at!: number | null
74 |
75 | @Column({ type: "varchar", nullable: true })
76 | token_type!: string | null
77 |
78 | @Column({ type: "varchar", nullable: true })
79 | scope!: string | null
80 |
81 | @Column({ type: "varchar", nullable: true })
82 | id_token!: string | null
83 |
84 | @Column({ type: "varchar", nullable: true })
85 | session_state!: string | null
86 |
87 | @ManyToOne(() => UserEntity, (user) => user.accounts, {
88 | createForeignKeyConstraints: true,
89 | })
90 | user!: UserEntity
91 | }
92 |
93 | @Entity({ name: "sessions" })
94 | export class SessionEntity {
95 | @PrimaryGeneratedColumn("uuid")
96 | id!: string
97 |
98 | @Column({ unique: true })
99 | sessionToken!: string
100 |
101 | @Column({ type: "uuid" })
102 | userId!: string
103 |
104 | @Column({ transformer: transformer.date })
105 | expires!: string
106 |
107 | @ManyToOne(() => UserEntity, (user) => user.sessions)
108 | user!: UserEntity
109 | }
110 |
111 | @Entity({ name: "verification_tokens" })
112 | export class VerificationTokenEntity {
113 | @PrimaryGeneratedColumn("uuid")
114 | id!: string
115 |
116 | @Column()
117 | token!: string
118 |
119 | @Column()
120 | identifier!: string
121 |
122 | @Column({ transformer: transformer.date })
123 | expires!: string
124 | }
125 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/src/utils.ts:
--------------------------------------------------------------------------------
1 | import type { Connection, ConnectionOptions } from "typeorm"
2 | import * as defaultEntities from "./entities"
3 |
4 | /** Ensure configOrString is normalized to an object. */
5 | export function parseConnectionConfig(
6 | configOrString: string | ConnectionOptions
7 | ): ConnectionOptions {
8 | if (typeof configOrString !== "string") {
9 | return {
10 | ...configOrString,
11 | entities: Object.values(configOrString.entities ?? defaultEntities),
12 | }
13 | }
14 |
15 | // If the input is URL string, automatically convert the string to an object
16 | // to make configuration easier (in most use cases).
17 | //
18 | // TypeORM accepts connection string as a 'url' option, but unfortunately
19 | // not for all databases (e.g. SQLite) or for all options, so we handle
20 | // parsing it in this function.
21 | try {
22 | const parsedUrl = new URL(configOrString)
23 | const config: any = {
24 | entities: Object.values(defaultEntities),
25 | }
26 |
27 | if (parsedUrl.protocol.startsWith("mongodb+srv")) {
28 | // Special case handling is required for mongodb+srv with TypeORM
29 | config.type = "mongodb"
30 | config.url = configOrString.replace(/\?(.*)$/, "")
31 | config.useNewUrlParser = true
32 | } else {
33 | config.type = parsedUrl.protocol.replace(/:$/, "")
34 | config.host = parsedUrl.hostname
35 | config.port = Number(parsedUrl.port)
36 | config.username = parsedUrl.username
37 | config.password = parsedUrl.password
38 | config.database = parsedUrl.pathname
39 | .replace(/^\//, "")
40 | .replace(/\?(.*)$/, "")
41 | config.options = {}
42 | }
43 |
44 | // This option is recommended by mongodb
45 | if (config.type === "mongodb") {
46 | config.useUnifiedTopology = true
47 | }
48 |
49 | // Prevents warning about deprecated option (sets default value)
50 | if (config.type === "mssql") {
51 | config.options.enableArithAbort = true
52 | }
53 |
54 | if (parsedUrl.search) {
55 | parsedUrl.search
56 | .replace(/^\?/, "")
57 | .split("&")
58 | .forEach((keyValuePair) => {
59 | let [key, value] = keyValuePair.split("=") as any
60 | // Converts true/false strings to actual boolean values
61 | if (value === "true") {
62 | value = true
63 | }
64 | if (value === "false") {
65 | value = false
66 | }
67 | config[key] = value
68 | })
69 | }
70 |
71 | return config
72 | } catch (error) {
73 | // If URL parsing fails for any reason, try letting TypeORM handle it
74 | return { url: configOrString } as any
75 | }
76 | }
77 |
78 | function entitiesChanged(
79 | prevEntities: any[] | undefined,
80 | newEntities: any[]
81 | ): boolean {
82 | if (prevEntities?.length !== newEntities?.length) return true
83 |
84 | for (let i = 0; i < prevEntities?.length; i++) {
85 | if (prevEntities[i] !== newEntities[i]) return true
86 | }
87 |
88 | return false
89 | }
90 |
91 | export async function updateConnectionEntities(
92 | connection: Connection,
93 | entities: any[]
94 | ) {
95 | if (!entitiesChanged(connection.options.entities, entities)) return
96 |
97 | // @ts-expect-error
98 | connection.options.entities = entities
99 |
100 | // @ts-expect-error
101 | connection.buildMetadatas()
102 |
103 | if (connection.options.synchronize !== false) {
104 | console.warn(
105 | "[next-auth][warn][adapter_typeorm_updating_entities]",
106 | "\nhttps://next-auth.js.org/warnings#adapter_typeorm_updating_entities"
107 | )
108 | await connection.synchronize()
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/custom-entities.ts:
--------------------------------------------------------------------------------
1 | import type { ValueTransformer } from "typeorm"
2 | import {
3 | Entity,
4 | PrimaryGeneratedColumn,
5 | Column,
6 | ManyToOne,
7 | OneToMany,
8 | } from "typeorm"
9 |
10 | const transformer: Record<"date" | "bigint", ValueTransformer> = {
11 | date: {
12 | from: (date: string | null) => date && new Date(parseInt(date, 10)),
13 | to: (date?: Date) => date?.valueOf().toString(),
14 | },
15 | bigint: {
16 | from: (bigInt: string | null) => bigInt && parseInt(bigInt, 10),
17 | to: (bigInt?: number) => bigInt?.toString(),
18 | },
19 | }
20 |
21 | @Entity({ name: "users" })
22 | export class UserEntity {
23 | @PrimaryGeneratedColumn("uuid")
24 | id!: string
25 |
26 | @Column({ type: "varchar", nullable: true })
27 | name!: string | null
28 |
29 | @Column({ type: "varchar", nullable: true, unique: true })
30 | email!: string | null
31 |
32 | @Column({ type: "varchar", nullable: true, transformer: transformer.date })
33 | emailVerified!: string | null
34 |
35 | @Column({ type: "varchar", nullable: true })
36 | role!: string | null
37 |
38 | @Column({ type: "varchar", nullable: true })
39 | phone!: string | null
40 |
41 | @Column({ type: "varchar", nullable: true })
42 | image!: string | null
43 |
44 | @OneToMany(() => SessionEntity, (session) => session.userId)
45 | sessions!: SessionEntity[]
46 |
47 | @OneToMany(() => AccountEntity, (account) => account.userId)
48 | accounts!: AccountEntity[]
49 | }
50 |
51 | @Entity({ name: "accounts" })
52 | export class AccountEntity {
53 | @PrimaryGeneratedColumn("uuid")
54 | id!: string
55 |
56 | @Column({ type: "uuid" })
57 | userId!: string
58 |
59 | @Column()
60 | type!: string
61 |
62 | @Column()
63 | provider!: string
64 |
65 | @Column()
66 | providerAccountId!: string
67 |
68 | @Column({ type: "varchar", nullable: true })
69 | refresh_token!: string
70 |
71 | @Column({ type: "varchar", nullable: true })
72 | access_token!: string | null
73 |
74 | @Column({
75 | nullable: true,
76 | type: "bigint",
77 | transformer: transformer.bigint,
78 | })
79 | expires_at!: number | null
80 |
81 | @Column({ type: "varchar", nullable: true })
82 | token_type!: string | null
83 |
84 | @Column({ type: "varchar", nullable: true })
85 | scope!: string | null
86 |
87 | @Column({ type: "varchar", nullable: true })
88 | id_token!: string | null
89 |
90 | @Column({ type: "varchar", nullable: true })
91 | session_state!: string | null
92 |
93 | @ManyToOne(() => UserEntity, (user) => user.accounts, {
94 | createForeignKeyConstraints: true,
95 | })
96 | user!: UserEntity
97 | }
98 |
99 | @Entity({ name: "sessions" })
100 | export class SessionEntity {
101 | @PrimaryGeneratedColumn("uuid")
102 | id!: string
103 |
104 | @Column({ unique: true })
105 | sessionToken!: string
106 |
107 | @Column({ type: "uuid" })
108 | userId!: string
109 |
110 | @Column({ transformer: transformer.date })
111 | expires!: string
112 |
113 | @ManyToOne(() => UserEntity, (user) => user.sessions)
114 | user!: UserEntity
115 | }
116 |
117 | @Entity({ name: "verification_tokens" })
118 | export class VerificationTokenEntity {
119 | @PrimaryGeneratedColumn("uuid")
120 | id!: string
121 |
122 | @Column()
123 | token!: string
124 |
125 | @Column()
126 | identifier!: string
127 |
128 | @Column({ transformer: transformer.date })
129 | expires!: string
130 | }
131 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/helpers.ts:
--------------------------------------------------------------------------------
1 | import type { ConnectionOptions } from "typeorm"
2 | import { ConnectionManager } from "typeorm"
3 | import type { TestOptions } from "../../../basic-tests"
4 | import * as defaultEntities from "../src/entities"
5 | import { parseConnectionConfig } from "../src/utils"
6 |
7 | export { defaultEntities }
8 |
9 | /** Set up Test Database */
10 | export function db(
11 | config: string | ConnectionOptions,
12 | entities: typeof defaultEntities = defaultEntities
13 | ): TestOptions["db"] {
14 | const connection = new ConnectionManager().create({
15 | ...parseConnectionConfig(config),
16 | entities: Object.values(entities),
17 | })
18 |
19 | const m = connection.manager
20 | return {
21 | connect: async () => await connection.connect(),
22 | disconnect: async () => await connection.close(),
23 | async user(id) {
24 | const user = await m.findOne(entities.UserEntity, id)
25 | return user ?? null
26 | },
27 | async account(provider_providerAccountId) {
28 | const account = await m.findOne(
29 | entities.AccountEntity,
30 | provider_providerAccountId
31 | )
32 | return account ?? null
33 | },
34 | async session(sessionToken) {
35 | const session = await m.findOne(entities.SessionEntity, { sessionToken })
36 | return session ?? null
37 | },
38 | async verificationToken(token_identifier) {
39 | const verificationToken = await m.findOne(
40 | entities.VerificationTokenEntity,
41 | token_identifier
42 | )
43 | if (!verificationToken) return null
44 | const { id: _, ...rest } = verificationToken
45 | return rest
46 | },
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
2 | // @ts-ignore
3 | import { parseConnectionString } from "../src/lib/config"
4 |
5 | const connectionString = "mysql://root:password@localhost:3306/next-auth"
6 |
7 | test("could parse connection string", () => {
8 | expect(parseConnectionString(connectionString)).toEqual(
9 | expect.objectContaining({
10 | type: "mysql",
11 | host: "localhost",
12 | port: 3306,
13 | username: "root",
14 | password: "password",
15 | database: "next-auth",
16 | })
17 | )
18 | })
19 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/init.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Init PostgreSQL container
4 | echo "Initializing container for PostgreSQL tests"
5 |
6 | PGUSER=nextauth
7 | PGDATABASE=nextauth
8 | PGPORT=5432
9 | PG_CONTAINER_NAME=next-auth-postgres-test
10 |
11 | docker run -d --rm \
12 | -e POSTGRES_USER=${PGUSER} \
13 | -e POSTGRES_DB=${PGDATABASE} \
14 | -e POSTGRES_HOST_AUTH_METHOD=trust \
15 | --name "${PG_CONTAINER_NAME}" \
16 | -p ${PGPORT}:5432 \
17 | postgres:13.3
18 |
19 | # Init MyDQL container
20 | echo "Initializing container for MySQL tests"
21 |
22 | MYSQL_DATABASE=next-auth
23 | MYSQL_ROOT_PASSWORD=password
24 | MYSQL_CONTAINER_NAME=next-auth-mysql-test
25 |
26 | docker run -d --rm \
27 | -e MYSQL_DATABASE=${MYSQL_DATABASE} \
28 | -e MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} \
29 | --name "${MYSQL_CONTAINER_NAME}" \
30 | -p 3306:3306 \
31 | mysql:8 \
32 | --default-authentication-plugin=mysql_native_password
33 |
34 |
35 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/mysql/index.custom.test.ts:
--------------------------------------------------------------------------------
1 | import { runBasicTests } from "../../../../basic-tests"
2 | import { TypeORMLegacyAdapter } from "../../src"
3 | import * as entities from "../custom-entities"
4 | import { db } from "../helpers"
5 | import { SnakeNamingStrategy } from "typeorm-naming-strategies"
6 |
7 | import type { ConnectionOptions } from "typeorm"
8 |
9 | const mysqlConfig: ConnectionOptions = {
10 | type: "mysql" as const,
11 | host: "localhost",
12 | port: 3306,
13 | username: "root",
14 | password: "password",
15 | database: "next-auth",
16 | synchronize: true,
17 | namingStrategy: new SnakeNamingStrategy(),
18 | }
19 |
20 | runBasicTests({
21 | adapter: TypeORMLegacyAdapter(mysqlConfig, {
22 | entities,
23 | }),
24 | db: db(mysqlConfig, entities),
25 | })
26 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/mysql/index.test.ts:
--------------------------------------------------------------------------------
1 | import { runBasicTests } from "../../../../basic-tests"
2 | import { TypeORMLegacyAdapter } from "../../src"
3 | import { db } from "../helpers"
4 |
5 | const mysqlConfig = {
6 | type: "mysql" as const,
7 | host: "localhost",
8 | port: 3306,
9 | username: "root",
10 | password: "password",
11 | database: "next-auth",
12 | synchronize: true,
13 | }
14 |
15 | runBasicTests({
16 | adapter: TypeORMLegacyAdapter(mysqlConfig),
17 | db: db(mysqlConfig),
18 | })
19 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/mysql/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | WAIT=20
4 | echo "Waiting ${WAIT} sec for MySQL db to be up..."
5 | sleep ${WAIT}
6 |
7 | set -eu
8 |
9 | echo "Started running MySQL tests with default models."
10 | jest tests/mysql/index.test.ts
11 | echo "Finished running MySQL tests with default models."
12 |
13 | echo "Started running MySQL tests with custom models."
14 | CUSTOM_MODEL=1 jest tests/mysql/index.custom.test.ts
15 | echo "Finished running MySQL tests with custom models."
16 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/postgresql/index.custom.test.ts:
--------------------------------------------------------------------------------
1 | import { runBasicTests } from "../../../../basic-tests"
2 | import { TypeORMLegacyAdapter } from "../../src"
3 | import * as entities from "../custom-entities"
4 | import { db } from "../helpers"
5 |
6 | const postgresConfig =
7 | "postgres://nextauth:password@localhost:5432/nextauth?synchronize=true"
8 |
9 | runBasicTests({
10 | adapter: TypeORMLegacyAdapter(postgresConfig, {
11 | entities,
12 | }),
13 | db: db(postgresConfig, entities),
14 | })
15 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/postgresql/index.test.ts:
--------------------------------------------------------------------------------
1 | import { runBasicTests } from "../../../../basic-tests"
2 | import { TypeORMLegacyAdapter } from "../../src"
3 | import { db } from "../helpers"
4 |
5 | const postgresConfig =
6 | "postgres://nextauth:password@localhost:5432/nextauth?synchronize=true"
7 |
8 | runBasicTests({
9 | adapter: TypeORMLegacyAdapter(postgresConfig),
10 | db: db(postgresConfig),
11 | })
12 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/postgresql/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | WAIT=10
4 | echo "Waiting ${WAIT} sec for PostgreSQL db to be up..."
5 | sleep ${WAIT}
6 |
7 | set -eu
8 |
9 | echo "Started running PostgreSQL tests with default models."
10 | jest tests/postgresql/index.test.ts
11 | echo "Finished running PostgreSQL tests with default models."
12 |
13 | echo "Started running PostgreSQL tests with custom models."
14 | CUSTOM_MODEL=1 jest tests/postgresql/index.custom.test.ts
15 | echo "Finished running PostgreSQL tests with custom models."
16 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/sqlite/index.custom.test.ts:
--------------------------------------------------------------------------------
1 | import { runBasicTests } from "../../../../basic-tests"
2 | import { TypeORMLegacyAdapter } from "../../src"
3 | import * as entities from "../custom-entities"
4 | import { db } from "../helpers"
5 |
6 | const sqliteConfig = {
7 | type: "sqlite" as const,
8 | name: "next-auth-test-memory",
9 | database: "./tests/sqlite/dev.db",
10 | synchronize: true,
11 | }
12 |
13 | runBasicTests({
14 | adapter: TypeORMLegacyAdapter(sqliteConfig, {
15 | entities,
16 | }),
17 | db: db(sqliteConfig, entities),
18 | })
19 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/sqlite/index.test.ts:
--------------------------------------------------------------------------------
1 | import { runBasicTests } from "../../../../basic-tests"
2 | import { TypeORMLegacyAdapter } from "../../src"
3 | import { db } from "../helpers"
4 | import { SnakeNamingStrategy } from "typeorm-naming-strategies"
5 |
6 | import type { ConnectionOptions } from "typeorm"
7 |
8 | const sqliteConfig: ConnectionOptions = {
9 | type: "sqlite" as const,
10 | name: "next-auth-test-memory",
11 | database: "./tests/sqlite/dev.db",
12 | synchronize: true,
13 | namingStrategy: new SnakeNamingStrategy(),
14 | }
15 |
16 | runBasicTests({
17 | adapter: TypeORMLegacyAdapter(sqliteConfig),
18 | db: db(sqliteConfig),
19 | })
20 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/sqlite/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu
4 |
5 | rm -f tests/sqlite/dev.db
6 |
7 | echo "Started running SQLite tests with default models."
8 | jest tests/sqlite/index.test.ts
9 | echo "Finished running SQLite tests with default models."
10 |
11 | rm -f tests/sqlite/dev.db
12 |
13 | echo "Started running SQLite tests with custom models."
14 | CUSTOM_MODEL=1 jest tests/sqlite/index.custom.test.ts
15 | echo "Finished running SQLite tests with custom models."
16 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tests/test.sh:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env bash
2 | #
3 | # Run parallel commands and fail if any of them fails.
4 | # shellcheck disable=SC2046
5 | # Based on: https://gist.github.com/mjambon/79adfc5cf6b11252e78b75df50793f24#gistcomment-3861511
6 |
7 | set -eu
8 |
9 | pids=()
10 |
11 | ./tests/init.sh
12 |
13 | ./tests/sqlite/test.sh & pids+=($!)
14 |
15 | ./tests/postgresql/test.sh & pids+=($!)
16 |
17 | ./tests/mysql/test.sh & pids+=($!)
18 |
19 | for _ in "${pids[@]}"; do
20 | if wait -n; then
21 | :
22 | else
23 | status=$?
24 | echo "One of the subprocesses exited with nonzero status $status. Aborting."
25 | for pid in "${pids[@]}"; do
26 | # Send a termination signal to all the children, and ignore errors
27 | # due to children that no longer exist.
28 | kill "$pid" 2> /dev/null || :
29 | done
30 | docker kill $(docker ps -q)
31 | exit "$status"
32 | fi
33 | done
34 |
35 | docker kill $(docker ps -q)
36 |
--------------------------------------------------------------------------------
/packages/typeorm-legacy/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "src",
5 | "outDir": "dist",
6 | "experimentalDecorators": true,
7 | "emitDecoratorMetadata": true,
8 | "stripInternal": true
9 | },
10 | "exclude": ["tests", "dist"]
11 | }
12 |
--------------------------------------------------------------------------------
/packages/upstash-redis/.env.example:
--------------------------------------------------------------------------------
1 | UPSTASH_REDIS_URL=
2 | UPSTASH_REDIS_KEY=
--------------------------------------------------------------------------------
/packages/upstash-redis/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | # 1.1.0 (2022-01-17)
7 |
8 | ### Bug Fixes
9 |
10 | - **upstash-redis:** expose environment variables in workflow ([#373](https://github.com/nextauthjs/adapters/issues/373)) ([fcee362](https://github.com/nextauthjs/adapters/commit/fcee36227fec4e42e818f104b06a3030838790da))
11 | - **upstash-redis:** fix deployment ([c2df2c8](https://github.com/nextauthjs/adapters/commit/c2df2c86b53f4e42a2bc1051256701ec7cc08fbd))
12 |
13 | ### Features
14 |
15 | - **upstash-redis:** add upstash-redis adapter ([#341](https://github.com/nextauthjs/adapters/issues/341)) ([f4a8464](https://github.com/nextauthjs/adapters/commit/f4a84644296f545c1dac16519337a6dc7718c88c))
16 |
--------------------------------------------------------------------------------
/packages/upstash-redis/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Upstash Redis Adapter - NextAuth.js
5 |
6 | Open Source. Full Stack. Own Your Data.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | ## Overview
16 |
17 | This is the Upstash Redis adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` and `@upstash/redis` packages. It is not a standalone package.
18 |
19 | ## Getting Started
20 |
21 | 1. Install `next-auth` and `@next-auth/upstash-redis-adapter` as well as `@upstash/redis` via NPM.
22 |
23 | ```js
24 | npm install next-auth @next-auth/upstash-redis-adapter @upstash/redis
25 | ```
26 |
27 | 2. Add the follwing code to your `pages/api/[...nextauth].js` next-auth configuration object.
28 |
29 | ```js
30 | import NextAuth from "next-auth"
31 | import { UpstashRedisAdapter } from "@next-auth/upstash-adapter"
32 | import upstashRedisClient from "@upstash/redis"
33 |
34 | const redis = upstashRedisClient("UPSTASH_REDIS_REST_URL", "UPSTASH_REDIS_REST_TOKEN")
35 |
36 | // For more information on each option (and a full list of options) go to
37 | // https://next-auth.js.org/configuration/options
38 | export default NextAuth({
39 | ...
40 | adapter: UpstashRedisAdapter(redis)
41 | ...
42 | })
43 | ```
44 |
45 | ## Using Multiple Apps with a Single Upstash Redis Instance
46 |
47 | The Upstash free-tier allows for only one Redis instance. If you have multiple Next-Auth connected apps using this instance, you need different key prefixes for every app.
48 |
49 | You can change the prefixes by passing an `options` object as the second argument to the adapter factory function.
50 |
51 | The default values for this object are:
52 |
53 | ```js
54 | const defaultOptions = {
55 | baseKeyPrefix: "",
56 | accountKeyPrefix: "user:account:",
57 | accountByUserIdPrefix: "user:account:by-user-id:",
58 | emailKeyPrefix: "user:email:",
59 | sessionKeyPrefix: "user:session:",
60 | sessionByUserIdKeyPrefix: "user:session:by-user-id:",
61 | userKeyPrefix: "user:",
62 | verificationTokenKeyPrefix: "user:token:",
63 | }
64 | ```
65 |
66 | Usually changing the `baseKeyPrefix` should be enough for this scenario, but for more custom setups, you can also change the prefixes of every single key.
67 |
68 | Example:
69 |
70 | ```js
71 | export default NextAuth({
72 | ...
73 | adapter: UpstashRedisAdapter(redis, {baseKeyPrefix: "app2:"})
74 | ...
75 | })
76 | ```
77 |
78 | ## Contributing
79 |
80 | We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
81 |
82 | ## License
83 |
84 | ISC
85 |
--------------------------------------------------------------------------------
/packages/upstash-redis/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("../../jest.config")
2 |
--------------------------------------------------------------------------------
/packages/upstash-redis/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/upstash-redis/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@next-auth/upstash-redis-adapter",
3 | "version": "1.1.0",
4 | "description": "Upstash adapter for next-auth. It uses Upstash's connectionless (HTTP based) Redis client.",
5 | "homepage": "https://next-auth.js.org",
6 | "repository": "https://github.com/nextauthjs/adapters",
7 | "bugs": {
8 | "url": "https://github.com/nextauthjs/adapters/issues"
9 | },
10 | "author": "github.com/kay-is",
11 | "main": "dist/index.js",
12 | "license": "ISC",
13 | "keywords": [
14 | "next-auth",
15 | "next.js",
16 | "oauth",
17 | "upstash",
18 | "redis"
19 | ],
20 | "private": false,
21 | "publishConfig": {
22 | "access": "public"
23 | },
24 | "scripts": {
25 | "test": "jest",
26 | "build": "tsc"
27 | },
28 | "files": [
29 | "README.md",
30 | "dist"
31 | ],
32 | "peerDependencies": {
33 | "@upstash/redis": "^0.2.1",
34 | "next-auth": "^4.0.1"
35 | },
36 | "devDependencies": {
37 | "@upstash/redis": "^0.2.1",
38 | "dotenv": "^10.0.0"
39 | },
40 | "dependencies": {
41 | "uuid": "^8.3.2"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/packages/upstash-redis/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | import upstashRedisClient from "@upstash/redis"
2 | import { runBasicTests } from "../../../basic-tests"
3 | import { reviveFromJson, UpstashRedisAdapter } from "../src"
4 | import "dotenv/config"
5 |
6 | const client = upstashRedisClient(
7 | process.env.UPSTASH_REDIS_URL,
8 | process.env.UPSTASH_REDIS_KEY
9 | )
10 |
11 | runBasicTests({
12 | adapter: UpstashRedisAdapter(client, { baseKeyPrefix: "testApp:" }),
13 | db: {
14 | async user(id: string) {
15 | const { data } = await client.get(`testApp:user:${id}`)
16 | return reviveFromJson(data)
17 | },
18 | async account({ provider, providerAccountId }) {
19 | const { data } = await client.get(
20 | `testApp:user:account:${provider}:${providerAccountId}`
21 | )
22 | return reviveFromJson(data)
23 | },
24 | async session(sessionToken) {
25 | const { data } = await client.get(`testApp:user:session:${sessionToken}`)
26 | return reviveFromJson(data)
27 | },
28 | async verificationToken(where) {
29 | const { data } = await client.get(
30 | `testApp:user:token:${where.identifier}`
31 | )
32 | return reviveFromJson(data)
33 | },
34 | },
35 | })
36 |
--------------------------------------------------------------------------------
/packages/upstash-redis/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "src",
5 | "outDir": "dist"
6 | },
7 | "exclude": ["tests", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2019",
4 | "module": "commonjs",
5 | "declaration": true,
6 | "strict": true,
7 | "esModuleInterop": true,
8 | "skipLibCheck": true,
9 | "forceConsistentCasingInFileNames": true
10 | }
11 | }
12 |
--------------------------------------------------------------------------------