Compare commits

...

20 Commits

Author SHA1 Message Date
Balázs Orbán
564b342f69 fix(docs): generate providers on docosaurus start 2021-02-16 15:42:27 +01:00
Balázs Orbán
63638d81dc docs: add sponsoring information 2021-02-16 15:42:27 +01:00
Balázs Orbán
28683015f1 docs: add links to README badges 2021-02-16 10:34:54 +01:00
Balázs Orbán
726c49603d chore: make next a prerelease channel 2021-02-16 10:20:46 +01:00
Balázs Orbán
a7113c6d3e chore: trigger release on main branch 2021-02-16 09:50:19 +01:00
Balázs Orbán
910514c6e2 chore: trigger release action on next branch 2021-02-15 21:51:17 +01:00
Balázs Orbán
b7cca484cf docs(provider): mention re-exporting config 2021-02-15 13:28:20 +01:00
Balázs Orbán
e293e786a8 fix(page): fallback to default error when no query param (#1303) 2021-02-11 22:25:09 +01:00
Balázs Orbán
82dd6ba3e4 feat(logger): introduce user configurable logger (#1294) 2021-02-11 14:50:53 +01:00
Balázs Orbán
6e28a07746 fix(client): reload after login/logout when url contains hash (#1298)
Co-authored-by: Thew Dhanat
2021-02-11 12:18:54 +01:00
Balázs Orbán
61047e3c14 chore: add CodeQL code analysis action 2021-02-11 09:58:22 +01:00
Balázs Orbán
dc5f3f481d chore(deps): upgrade test dependencies 2021-02-10 21:04:36 +01:00
Balázs Orbán
0343344802 chore: add new PR labels 2021-02-10 20:56:22 +01:00
Balázs Orbán
134a95a4bd docs(provider): auto-generate providers list (#1295)
* docs: ignore providers.json

* chore: generate providers.json from front-matter

* chore: remove autogenerated file

* docs(provider): rename vk.com to VK

* docs: encourage adding new providers
2021-02-10 20:43:04 +01:00
Joshua Payette
52a4bd97cd docs(provider): Update azure-ad-b2c (#1288)
It seems that the AZURE_TENANT_NAME env var is not required for next-auth.  This update removes it.

Co-authored-by: Balázs Orbán <info@balazsorban.com>
2021-02-10 00:57:43 +01:00
Benjamin Bender
87d43e4038 docs: Update client.md (#1289)
Fix typo on getProviders()
2021-02-10 00:37:27 +01:00
Balázs Orbán
68695af1f3 chore: update release flow 2021-02-09 22:08:52 +01:00
Balázs Orbán
76df2b5e70 chore: disable semantic releases temporarily 2021-02-09 20:52:01 +01:00
Balázs Orbán
8bd9d87633 feat: new release (#1259)
* feat: simplify NextAuth instantiation (#911)

* feat: allow react 17 as a peer dependency (#819)

Co-authored-by: Balázs Orbán <info@balazsorban.com>

* docs: update for Now to Vercel (#847)

Vercel archived their now packages a while back, so you can use vercel env pull to pull in the .env

* docs: fix discord example code (#850)

* docs: fix typo in callbacks.md (#815)

This is a simple typographical error changed accesed to accessed

* fix: update nodemailer version in response to CVE. (#860)

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-7769 reports a high-severity issue with the current version of nodemailer. This should be merged and released right away if possible.

* fix: ensure Images are produced for discord (#734)

* fix: update Okta routes (#763)

the current routing for the Okta provider does not follow the standard
set by Okta, and as such doesn't allow for custom subdomains. this
update amends the routes to allow for customer subdomains, and also
aligns next-auth with Okta's documentation.

* fix(provider): handle no profile image for Spotify (#914)

* chore(deps): upgrade "standard"

* style(lint): run lint fix

* fix(provider): optional chain Spotify provider profile img

* Merge main into canary (#917)

* chore: use stale label, instead of wontfix

* chore: add link to issue explaining stalebot

* chore: fix typo in stalebot comment

* chore: run build GitHub Action on canary also

* chore: run build GitHub Actions on canary as well

* chore: add reproduction section to questions

* docs: Update default ports for support Databases (#839)

https://next-auth.js.org/configuration/databases

* Fix for Reddit Authentication (#866)

* Fixed Reddit Authentication

* updated fix for build test

* updated buffer to avoid deprecation message

* Updated for passing tests

* WIP: Update Docusaurus + Site dependencies (#802)

* update: deps

* fix: broken link

* fix: search upgrade change

* Include callbackUrl in newUser page (#790)

* Include callbackUrl in newUser page

* Update src/server/routes/callback.js

Co-authored-by: Iain Collins <me@iaincollins.com>

* Update src/server/routes/callback.js

Co-authored-by: Iain Collins <me@iaincollins.com>

Co-authored-by: Iain Collins <me@iaincollins.com>
Co-authored-by: Nico Domino <yo@ndo.dev>

* add(db): Add support for Fauna DB (#708)

* Add support for Fauna DB

* Add integration tests

Co-authored-by: Nico Domino <yo@ndo.dev>

* feat(provider): add netlify (#555)

Co-authored-by: styxlab <cws@DE01WP777.scdom.net>
Co-authored-by: Balázs Orbán <info@balazsorban.com>

* Bump next from 9.5.3 to 9.5.4 in /test/docker/app (#759)

Bumps [next](https://github.com/vercel/next.js) from 9.5.3 to 9.5.4.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v9.5.3...v9.5.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nico Domino <yo@ndo.dev>

* feat(provider): Add Bungie (#589)

* Add Bungie provider

* Use absolute URL for images

* Correct image URL and use consistent formatting

Co-authored-by: Nico Domino <yo@ndo.dev>

* feat: add foursquare (#584)

* feat(provider): Add Azure Active Directory B2C (#921)

* add provider: Microsoft

* documentation

* support no tenant setup

* fix code style

* chore: rename Microsoft provider to AzureADB2C

* chore: alphabetical order in providers/index

* doc: add provider to FAQ

* update(provider): Update Slack provider to use V2 OAuth endpoints (#895)

* Update Slack to v2 authorize urls, option for additional authorize params
* acessTokenGetter + documentation

* refactor(db): update Prisma calls to support 2.12+ (#881)

Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Nico Domino <yo@ndo.dev>

* chore(dep): Bump highlight.js from 9.18.1 to 9.18.5 (#880)

Bumps [highlight.js](https://github.com/highlightjs/highlight.js) from 9.18.1 to 9.18.5.
- [Release notes](https://github.com/highlightjs/highlight.js/releases)
- [Changelog](https://github.com/highlightjs/highlight.js/blob/9.18.5/CHANGES.md)
- [Commits](https://github.com/highlightjs/highlight.js/compare/9.18.1...9.18.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Nico Domino <yo@ndo.dev>

* chore: disallow issues without template

* chore: add note about conveting questions to discussions

* chore: create PULL_REQUEST_TEMPLATE.md

* chore: reword PR template

* feat: Store user ID in sub claim of default JWT (#784)

This allows us to check if the user is signed in when using JWTs

Part of #625

* docs: fix incorrect references in cypress docs (#932)

* chore: use stale label, instead of wontfix

* chore: add link to issue explaining stalebot

* chore: fix typo in stalebot comment

* chore: run build GitHub Action on canary also

* chore: run build GitHub Actions on canary as well

* chore: add reproduction section to questions

* feat(provider): Add Azure Active Directory B2C (#809)

* add provider: Microsoft

* documentation

* support no tenant setup

* fix code style

* chore: rename Microsoft provider to AzureADB2C

* chore: alphabetical order in providers/index

* Revert "feat(provider): Add Azure Active Directory B2C (#809)" (#919)

This reverts commit 6e6a24a7af.

* chore: add myself to the contributors list 🙈

* docs: fix incorrect references in cypress docs

* chore: add additional docs clarification

Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Vladimir Evdokimov <evdokimov.vladimir@gmail.com>

* feat: Display error if no [...nextauth].js found (#678)

* Display error if no [...nextauth].js found

fixes #647

* Log the error and describe it inside errors.md

Co-authored-by: Balázs Orbán <info@balazsorban.com>

* chore(deps): Bump ini from 1.3.5 to 1.3.8 in /www (#953)

Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.8)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* docs: fix typo Adapater -> Adapter (#960)

Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Vladimir Evdokimov <evdokimov.vladimir@gmail.com>

* docs: We have twice the word "side" (#964)

* chore: use stale label, instead of wontfix

* chore: add link to issue explaining stalebot

* chore: fix typo in stalebot comment

* chore: run build GitHub Action on canary also

* chore: run build GitHub Actions on canary as well

* chore: add reproduction section to questions

* feat(provider): Add Azure Active Directory B2C (#809)

* add provider: Microsoft

* documentation

* support no tenant setup

* fix code style

* chore: rename Microsoft provider to AzureADB2C

* chore: alphabetical order in providers/index

* Revert "feat(provider): Add Azure Active Directory B2C (#809)" (#919)

This reverts commit 6e6a24a7af.

* chore: add myself to the contributors list 🙈

* We have twice the word "side"

Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Vladimir Evdokimov <evdokimov.vladimir@gmail.com>

* docs: Correcting a typo. "available" Line 70 (#965)

* chore: use stale label, instead of wontfix

* chore: add link to issue explaining stalebot

* chore: fix typo in stalebot comment

* chore: run build GitHub Action on canary also

* chore: run build GitHub Actions on canary as well

* chore: add reproduction section to questions

* feat(provider): Add Azure Active Directory B2C (#809)

* add provider: Microsoft

* documentation

* support no tenant setup

* fix code style

* chore: rename Microsoft provider to AzureADB2C

* chore: alphabetical order in providers/index

* Revert "feat(provider): Add Azure Active Directory B2C (#809)" (#919)

This reverts commit 6e6a24a7af.

* chore: add myself to the contributors list 🙈

* Correcting a typo. "available" Line 70

Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Vladimir Evdokimov <evdokimov.vladimir@gmail.com>

* chore: hide comments from pull request template

* Update README.md

Updated the readme to include the projects logo, fixed some typos, and added license info and contributor image.

* feat: add strava provider (#986)

* Add Strava as a provider

* Add documentation for Strava provider

* Fix lint errors

Co-authored-by: Paul Kenneth Kent <paul@ventureharbour.com>

* Update README.md

* Update README.md

* feat: add semantic-release (#920)

* chore(release): change semantic-release/git to semantic-release/github

* docs(database): add mssql indexes in docs, fix typos (#925)

* added mssql indexes in docs, fixed typo

* docs: fix typo in www/docs/schemas/mssql.md

Co-authored-by: Balázs Orbán <info@balazsorban.com>

* chore(release): delete old workflow

* chore(release): trigger release on docs type

* fix: treat user.id as optional param (#1010)

* fix(adapter): use findOne for typeorm (#1014)

* Change image to text from varchar (#777)

Co-authored-by: Nico Domino <yo@ndo.dev>

* feat(db): make Fauna DB collections & indexes configurable (#968)

* Add collections & indexes overrides for Fauna DB

* Fix the name of the verification token index

Co-authored-by: Florian Michaut <florian@coding-days.com>

* docs: Remove unnecessary promises (#915)

* feat: allow to return string in signIn callback (#1019)

* docs: small update to sign in/out examples (#1016)

* Update examples in client.md

* Update more examples

Co-authored-by: Balázs Orbán <info@balazsorban.com>

* docs: update contributing information [skip release] (#1011)

* docs: update CONTRIBUTING.md

* docs:  use db instead of database for more space

* docs: update CONTRIBUTING.md

* docs: update PR template

* docs: add note about skipping a release

* docs: fix typos in CONTRIBUTING.md [skip release]

* refactor: code base improvements (#959)

* chore: fix casing of OAuth

* refacotr: simplify default callbacks lib file

* refactor: use native URL instead of string concats

* refactor: move redirect to res.redirect, done to res.end

* refactor: move options to req

* refactor: improve IntelliSense, name all functions

* fix(lint): fix lint errors

* refactor: remove jwt-decode dependency

* refactor: refactor some callbacks to Promises

* revert: "refactor: use native URL instead of string concats"

Refs: 690c55b04089e4f3157424c816d43ee4cecb77a0

* chore: misc changes

Co-authored-by: Balazs Orban <balazs@nhi.no>

* feat(provider): Add Mail.ru OAuth Service Provider and Callback snippet (#522)

* Update callback.js

- Fix Mail.ru bug (missing request parameter: access_token)

Note: setGetAccessTokenProfileUrl should be added to Mail.ru provider to enable support.

* Add Mail.ru OAuth Service Provider

* Update callbacks.md

- Fix broken callbacks snippet.

* Update callback.js

- Bug fix https://github.com/nextauthjs/next-auth/pull/522#issuecomment-669851914
- Minor refactoring.

* Fix: Code linting.

* Update callback.js

Improve approach for building of URL based review recommendation.

* Feat: Reduce API surface expansion

Make use of provider.id === "mailru" as suggested in review discussion in place of setGetAccessTokenProfileUrl.

* Fix: Code linting

* feat: forward id_token to jwt and signIn callbacks (#1024)

* chore: add auto labeling to PRs [skip release] (#1025)

* chore: add auto labeling to PRs [skip release]

* chore: allow any file type for test label to be added

* chore: rename labeler.yaml to labeler.yml [skip release]

* fix: miscellaneous bugfixes (#1030)

* fix: use named params to fix order

* fix: avoid recursive redirects

* fix: revert to use parsed baseUrl

* fix: avoid recursive res.end calls

* fix: use named params in renderPage

* fix: promisify lib/oauth/callback result

* fix: don't chain on res.end on non-chainable res methods (#1031)

* docs: add powered by vercel logo [skip release]

* chore: run tests on canary [skip release]

* docs: misc improvements [skip release] (#1043)

* refactor: code base improvements 2 (#1045)

* fix: trigger release

* fix: use authorizationUrl correctly

* feat(provider): reduce user facing API (#1023)

Co-authored-by: Balazs Orban <balazs@nhi.no>

* fix: remove async from NextAuth default handler

This function should not return a Promise

* feat(provider): add vk.com provider (#1060)

* feat(provider): add vk.com provider

* refactor(provider): reduce vk.com provider api

* refactor: code base improvements 3 (#1072)

* refactor: extend res.{end,send,json}, redirect

* refactor: chain res methods, remove unnecessary ones

* refactor: simplify oauth callback signature

* refactor: code simplifications

* refactor: re-export everything from routes in one

* refactor: split up main index.js to multiple files

* refactor: simplify passing of provider(s) around

* refactor: extend req with callbackUrl inline

* refactor: simplify page rendering

* refactor: move error page redirects to main file, simplify renderer

* refactor: inline req.options definition

* refactor: simplify error fallbacks

* refactor: remove else branches and unnecessary try..catch

* refactor: add docs, and simplify jwt functions

* refactor: prefer errors object over switch..case in signin page

* feat: log all params sent to logger instead of only first

* refactor: fewer lines input validation

* refactor: remove even more unnecessary else branches

* feat: improve package development experience (#1064)

* chore(deps): add next and react to dev dependencies

* chore: move build configs to avoid crash with next dev

* chore: add next js dev app

* chore: remove .txt extension from LICENSE file

* chore: update CONTRIBUTING.md

* chore: watch css under development

* style(lint): run linter on index.css

* chore: fix some imports for dev server

* refactor: simplify client code

* chore: mention VSCode extension for linting

* docs: reword CONTRIBUTING.md

* chore: ignore linting pages and components

* fix: pass csrfToken to signin renderer

* feat: replace blur/focus event to visibility API for getSession (#1081)

* docs: clarify .env usage in CONTRIBUTING.md [skip release] (#1085)

* docs: improve FAQ docs [skip release]

* chore: update caiuse-lite db

* docs: update  some urls in the docs [skip release]

* feat(pages): add dark theme support (#1088)

* feat(pages): add dark theme support

* docs: document theme option

* chore: remove ts-check from dev app

* style(pages): fix some text colors in dark mode

* feat(provider): add LINE provider (#1091)

* refactor: be explicit about path in jsonconfig [skip release]

* refactor: show signin page in dev app [skip release]

* fix: export getSession [skip release]

somehow the default export does not work in the dev app

* style: make p system theme aware [skip release]

* feat(provider): finish Reddit provider and add documentation (#1094)

* Create reddit.md

* uncommented profile callback

* Update reddit.md

* fix lint issues

* added reddit provider

* added reddit provider

* Add Reddit Provider

For some reason a bunch of providers got deleted in the last commit

* Add Reddit Provider

* Add Reddit Provider

* chore: define providers in single file for docs [skip release]

* chore: Comply to Vercel Open Source sponsorship [skip release] (#1087)

* added banner

* Changed banner image allignment

* changed location of banner again

* added to acknowledgement

* added to acknowledgement 1

* changed image size

* k

* l

* s

* s

* .

* added link to the banner in readme.md

* fixed image redirect

* fixed image allignment

* made changes in readme and index.js

* Changed the source of the banner image

* added banner to the footer of the site

* chore: fix lint issues [skip release]

* feat: add native hkdf (#1124)

* feat: add native hkdf

* feat: import only needed to do hkdf

* feat: tweak digest and arguments

* chore(deps): upgrade typeorm to v0.2.30 (#1145)

* docs: remove v1 documentation (#1142)

* chore(adapters): remove fauna (#1148)

* feat: forward signIn auth params to /authorize (#1149)

* refactor: authorisation -> authorization

* feat: forward authorizationParams from signIn function

* refactor: take auth params as third argument

* docs: document signIn authorizationParams

* fix(adapter): fix ISO Datetime type error in Prisma updateSession (#640)

Co-authored-by: Nico Domino <yo@ndo.dev>
Co-authored-by: Balázs Orbán <info@balazsorban.com>

* feat(provider): add option to generate email verification token (#541)

* Add option to generate email verification token

* chore: remove unused import

* refactor: define default generateVerificationToken in-place

* refactor: define default generateVerificationToken in-place

Co-authored-by: Nico Domino <yo@ndo.dev>
Co-authored-by: Balázs Orbán <info@balazsorban.com>

* docs: update info about TypeScript [skip release]

* feat: add PKCE support (#941)

* chore(deps): upgrade dependencies

* chore(deps): add pkce-challenge

* feat(pkce): initial implementation of PCKE support

* chore: remove URLSearchParams

* chore(deps): upgrade lockfile

* refactor: store code_verifier in a cookie

* refactor: add pkce handlers

* docs: add PKCE documentation

* chore: remove unused param

* chore: revert unnecessary code change

* fix: correct variable names

* fix: correct logger import

* feat(provider): add Salesforce provider (#1027)

* docs(provider): add Salesforce provider

* fix(provider): use authed_user on slack instead of spotify (#1174)

* fix: use startsWith for protocol matching in parseUrl

closes #842

* fix: fix lint issues

* docs: clear things up around using access_token [skip release]

#1078

* docs: fix typo in callbacks.md [skip release]

* chore(provider): remove Mixer (#1178)

"Thank you to our amazing community and Partners.
As of July 22, the Mixer service has closed."

* feat(provider): re-add state, expand protection provider options  (#1184)

* refactor: move OAuthCallbackError to errors file

* refactor: improve pkce handling

* feat(provider): re-introduce state to provider options

* docs(provider): mention protection options "state" and "none"

* docs(provider): document state property deprecation

* fix: only add code_verifier param if protection is pkce

* docs: explain state deprecation better

* chore: unify string

* fix: send /authorize params through url

* fix: Add a null check to the window 'storage' event listener (#1198)

* Add a null check to the window 'storage' event listener

While testing in Cypress it's possible to receive a null value on Storage Events when 'clear' is called and will cause errors as seen in #1125.

* Update index.js

typo

* Update src/client/index.js

Co-authored-by: Balázs Orbán <info@balazsorban.com>

* formatting

Co-authored-by: Balázs Orbán <info@balazsorban.com>

* docs(provider): fix typos in providers code snippets [skip release] (#1204)

* docs(adapter): add adapter repo to documentation [skip release] (#1173)

* docs(adapter): add adapter repo to documentation

* docs(adapter): elaborate on custom repo

* fix: forward second argument to fetch body in signIn

fixes #1206

* docs: Fix grammar in "Feature Requests" section of FAQs [skip release] (#1212)

* refactor: provide raw idToken through account object (#1211)

* refactor: provide raw idToken through account object

* docs: clear up accessToken naming

* refactor: provide raw token response to account

* chore: fix grammar in comments

* feat: send all params to logger function (#1214)

* feat(provider): Add Medium (#1213)

* fix: leave accessTokenExpires as null

Forwarding expires_in as is to accessTokenExpires has shown to cause issues with Prisma, and maybe with other flows as well. Setting it back to `null` for now. We still forward `expires_in`, so users can use it if they want to.

Fixes #1216

* docs: more emphasis on req methods [skip release]

* docs: remove announcement bar [skip release]

* fix: make OAuth 1 work after refactoring (#1218)

* chore: add twitter provider to dev app

* feat: bind client instance to overriden methods

* fix: don't add extra params to getOAuthRequestToken

* chore: add twitter to env example, add secret gen instructions

* docs: Update Providers.Credential Example Block [skip release] (#1225)

Closing curly bracket where it should have been a square bracket.

* feat(provider): option to disable client-side redirects (credentials) (#1219)

* chore: add credentials provider to dev app

* feat: add redirect option to signIn, signOut

* feat: set correct status codes for credentials errors

* chore: add credentials page to dev app

* fix: support any provider name for credentials

* feat(ts): preliminary TypeScript support (#1223)

* chore: replace standard with ts-standard

* feat(ts): add some initial types

* feat(ts): import and use types

* chore: allow global fetch through package.json

* chore: upgrade lint scripts to use ts-standard

* chore: run linter on dev app

* chore(ts): satisfy dev Next.js server for TS

* fix: add eslint as dev dependency

* fix(lint): ignore next-env.d.ts from linting

* feat(ts): improve cookies options types

* fix: run linter with fix

* feat(provider): add EVE Online provider (#1227)

* Adding EVEOnline provider

* Adding EVEOnline provider

* Adding EVEOnline provider

* Adding EVEOnline provider

* Adding EVEOnline provider

* Adding EVEOnline provider

* Adding EVEOnline provider

* Adding EVEOnline provider

Co-authored-by: Gerald McNicholl <gerald.mcnicholl@xero.com>

* docs: clarify custom pages usage [skip release] (#1239)

* docs(provider): Update Atlassian docs (#1255)

* docs: Update Atlassian docs [skip release]

* Update atlassian.md

* fix(provider): okta client authentication (#1257)

* fix: okta client authentication

* chore: run lint fix

* Update pages/api/auth/[...nextauth].js

Co-authored-by: Balázs Orbán <info@balazsorban.com>

Co-authored-by: mgraser <matt.graser@mlb.com>
Co-authored-by: Balázs Orbán <info@balazsorban.com>

* chore: don't sync labels with labeler [skip release]

manually added PR labels were constantly removed on new commits/builds, this hopefully fixes that

* fix(provider): add verificationRequest flag to email signIn callback (#1258)

* fix(ui): use color text var for input color (#1260)

Co-authored-by: Archit Khode <archit.khode@gmail.com>

* docs: Minor text error fixed [skip release] (#1263)

* feat(provider): update session when signIn/signOut successful (#1267)

* feat(provider): update session when login/logout successful

* chore: remove manual page reload from dev app

* docs(client): document redirect: false

* fix(page): fix typo in error page

* Merge pull request from GHSA-pg53-56cg-4m8q

* fix(adapter): Verify identifier as well as token in Prisma adapter

* feat(adapter): Improve typeorm adapter

Improve conditional check in TypeORM adapter.

This should have no impact in practice but sets  a good example.

* docs(adapter): Update Prisma docs [skip release] (#1279) (#1283)

Co-authored-by: Iain Collins <me@iaincollins.com>

* docs(provider): Update azure-ad-b2c.md [skip release] (#1280)

* docs(adapter): Update Prisma docs (#1279)

* Update azure-ad-b2c.md

add hint for redirection URL, otherwise difficult to find out

* Update azure-ad-b2c.md

changed .env ro .env.local as per recommendation

* Update azure-ad-b2c.md

* Update azure-ad-b2c.md

* Update azure-ad-b2c.md

* update conf in .env.local 

follow the .env guidelines

* Update azure-ad-b2c.md

* Create azure-ad-b2c.md

* Create azure-ad-b2c.md

* Update azure-ad-b2c.md

Co-authored-by: Iain Collins <me@iaincollins.com>

* docs: Change "docs" to "documentation"

* fix(provider): Fixes for email sign in (#1285)

* fix(adapter): Fix Prisma delete

Must use Prsima deleteMany() instead of delete() with multiple clauses.

* feat: Update example project

Update example project to make it easier to test with database adapters.

* fix(ui): Fix message text in light / auto theme

Info message text is always on the same background (blue) on both themes so should always be white.

* docs: Update example .env [skip release]

* feat: Update Prisma peerOptionalDependencies

* docs: trigger release

Co-authored-by: Luke Lau <luke_lau@icloud.com>
Co-authored-by: James Perkins <jamesperkins@hey.com>
Co-authored-by: Joshua K. Martinez <joshkmartinez@gmail.com>
Co-authored-by: Pauldic <Pauldiconline@yahoo.com>
Co-authored-by: Josh Padnick <josh@gruntwork.io>
Co-authored-by: Daggy1234 <arnav.jindal7@gmail.com>
Co-authored-by: Alan Ray <71240883+ohheyalanray@users.noreply.github.com>
Co-authored-by: Manish Chiniwalar <manishrc@users.noreply.github.com>
Co-authored-by: Aymeric <34040599+afoyer@users.noreply.github.com>
Co-authored-by: Nico Domino <yo@ndo.dev>
Co-authored-by: Fabrizio Ruggeri <ramiel@users.noreply.github.com>
Co-authored-by: Iain Collins <me@iaincollins.com>
Co-authored-by: Joseph Vaughan <Joev-@users.noreply.github.com>
Co-authored-by: Joost Jansky <styxlab@users.noreply.github.com>
Co-authored-by: styxlab <cws@DE01WP777.scdom.net>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: RobertCraigie <robertcraigie30@gmail.com>
Co-authored-by: Joe Bell <joe@joebell.co.uk>
Co-authored-by: Vladimir Evdokimov <evdokimov.vladimir@gmail.com>
Co-authored-by: Cathy Chen <cathykaichen@gmail.com>
Co-authored-by: Kristóf Poduszló <kripod@protonmail.com>
Co-authored-by: Haldun Anil <haldunanil@users.noreply.github.com>
Co-authored-by: Jakub Naskręski <36169811+kleyu@users.noreply.github.com>
Co-authored-by: imgregduh <imgregorywong@gmail.com>
Co-authored-by: pkabore <paulkabore333@gmail.com>
Co-authored-by: Paul Kenneth Kent <pkennethkent@gmail.com>
Co-authored-by: Paul Kenneth Kent <paul@ventureharbour.com>
Co-authored-by: Balazs Orban <balazs@nhi.no>
Co-authored-by: Junior Vidotti <jrvidotti@gmail.com>
Co-authored-by: Yuma Matsune <yuma.matsune@gmail.com>
Co-authored-by: Ben West <Xodarap@users.noreply.github.com>
Co-authored-by: Florian Michaut <florianmichaut@gmail.com>
Co-authored-by: Florian Michaut <florian@coding-days.com>
Co-authored-by: Melanie Seltzer <melleh11@gmail.com>
Co-authored-by: Didi Keke <nyedidikeke@users.noreply.github.com>
Co-authored-by: Evgeniy Boreyko <boreykojenya@yandex.ru>
Co-authored-by: Alex B <lnikell@gmail.com>
Co-authored-by: Ben <5271788+bebax@users.noreply.github.com>
Co-authored-by: suraj10k <63460026+suraj10k@users.noreply.github.com>
Co-authored-by: t.kuriyama <koolii0909@gmail.com>
Co-authored-by: Yuri Gor <YuriGor@users.noreply.github.com>
Co-authored-by: Radhika <56536997+96RadhikaJadhav@users.noreply.github.com>
Co-authored-by: Henrik Wenz <HaNdTriX@users.noreply.github.com>
Co-authored-by: Zhao Lei <firede@firede.com>
Co-authored-by: Mohamed El Mahallawy <mmahalwy@gmail.com>
Co-authored-by: Dillon Mulroy <dillon.mulroy@gmail.com>
Co-authored-by: Carmelo Scandaliato <8927157+cascandaliato@users.noreply.github.com>
Co-authored-by: Aishah <aissshah@outlook.com>
Co-authored-by: Samson Zhang <wwsamson@yahoo.com>
Co-authored-by: Vova <volodimir.partytskyi@gmail.com>
Co-authored-by: Cody Ogden <cody@codyogden.com>
Co-authored-by: geraldm74 <gerald_mcnicholl@yahoo.com>
Co-authored-by: Gerald McNicholl <gerald.mcnicholl@xero.com>
Co-authored-by: Jeremy Caine <jezcaine@gmail.com>
Co-authored-by: Matthew Graser <mdgraser@gmail.com>
Co-authored-by: mgraser <matt.graser@mlb.com>
Co-authored-by: Kristofor Carle <kris@maphubs.com>
Co-authored-by: Archit Khode <arkits@outlook.com>
Co-authored-by: Archit Khode <archit.khode@gmail.com>
Co-authored-by: Daniel Gadd <danielgadd@outlook.com>
Co-authored-by: Robert Hufsky <Robert.Hufsky@gmx.net>
2021-02-09 15:47:47 +01:00
Iain Collins
6af40e3fe2 docs(adapter): Update Prisma docs (#1279) 2021-02-08 19:30:32 +00:00
73 changed files with 2718 additions and 4933 deletions

View File

@@ -1,8 +1,13 @@
# Rename file to .env.local and populate values
# Rename file to .env.local (or .env) and populate values
# to be able to run the dev app
NEXTAUTH_URL=http://localhost:3000
SECRET= Linux: `openssl rand -hex 32` or https://generate-secret.now.sh/32
# You can use `openssl rand -hex 32` or
# https://generate-secret.now.sh/32 to generate a secret.
# Note: Changing a secret may invalidate existing sessions
# and/or verificaion tokens.
SECRET=
AUTH0_ID=
AUTH0_DOMAIN=
@@ -12,4 +17,17 @@ GITHUB_ID=
GITHUB_SECRET=
TWITTER_ID=
TWITTER_SECRET=
TWITTER_SECRET=
# Example configuration for a Gmail account (will need SMTP enabled)
EMAIL_SERVER=smtps://user@gmail.com:password@smtp.gmail.com:465
EMAIL_FROM=user@gmail.com
# You can use any of these as the "DATABASE_URL" for
# databases started with Docker using `npm run db:start`.
# Note: If using with Prisma adapter, you need to use a `.env`
# file rather than a `.env.local` file to configure env vars.
# Postgres: DATABASE_URL=postgres://nextauth:password@127.0.0.1:5432/nextauth?synchronize=true
# MySQL: DATABASE_URL=mysql://nextauth:password@127.0.0.1:3306/nextauth?synchronize=true
# MongoDB: DATABASE_URL=mongodb://nextauth:password@127.0.0.1:27017/nextauth?synchronize=true
DATABASE_URL=

14
.github/labeler.yml vendored
View File

@@ -19,3 +19,17 @@ databases:
- test/docker/databases/**/*
- www/docs/configuration/databases.md
- test/fixtures/**/*
core:
- src/**/*
style:
- src/css/**/*
client:
- src/client/**/*
- www/docs/getting-started/client.md
pages:
- src/server/pages/**/*
- www/docs/configuration/pages.md

View File

@@ -1,31 +1,30 @@
# Simple check that the build is valid and no linting errors.
# Currently is run as a seperate workflow as it's fast to fail.
name: Build Test
name: Lint/Build
on:
push:
branches:
- main
- canary
- next
pull_request:
branches:
branches:
- main
- canary
- next
jobs:
build:
lint-and-build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x, 12.x, 14.x]
node-version: [10, 12, 14]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build
- name: Install dependencies
uses: bahmutov/npm-install@v1
- run: npm run lint
- run: npm run build

67
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@@ -0,0 +1,67 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ main, next ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '43 17 * * 2'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# 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
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@@ -2,9 +2,10 @@ name: Integration Test
on:
push:
branches: [ main, canary ]
branches:
- main
- next
pull_request:
branches: [ main, canary ]
jobs:
test:
@@ -28,7 +29,7 @@ jobs:
strategy:
matrix:
node-version: [12.x]
node-version: [10, 12, 14]
steps:
- uses: actions/checkout@v2
@@ -37,8 +38,8 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
# Install dependencies
- run: npm ci
- name: Install dependencies
uses: bahmutov/npm-install@v1
# Run tests (build library, build + start test app in Docker, run tests)
- run: npm test

View File

@@ -9,4 +9,3 @@ jobs:
- uses: actions/labeler@main
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
sync-labels: true

View File

@@ -2,29 +2,25 @@ name: Release
on:
push:
branches:
- main
- canary
- 'main'
- 'next'
- '3.x'
pull_request:
jobs:
release:
name: Release
runs-on: ubuntu-20.04
name: 'Release'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: 12
node-version: 14
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Build
run: npm run build
- name: Release
uses: bahmutov/npm-install@v1
- run: npm run build
- run: npx semantic-release@17
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
NPM_TOKEN: ${{secrets.NPM_TOKEN}}

6
.gitignore vendored
View File

@@ -24,6 +24,7 @@ node_modules
.docusaurus
.cache-loader
.next
www/providers.json
# VS
/.vs/slnx.sqlite-journal
@@ -33,4 +34,7 @@ node_modules
# GitHub Actions runner
/actions-runner
/_work
/_work
# Prisma migrations
/prisma/migrations

View File

@@ -1,39 +0,0 @@
{
"branches": [
"main",
{ "name": "canary", "prerelease": true }
],
"plugins": [
["@semantic-release/commit-analyzer", {
"preset": "conventionalcommits",
"releaseRules": [
{ "breaking": true, "release": "major" },
{ "revert": true, "release": "patch" },
{ "type": "feat", "release": "minor" },
{ "type": "fix", "release": "patch" },
{ "type": "perf", "release": "patch" },
{ "type": "docs", "release": "patch" }
]
}],
["@semantic-release/release-notes-generator", {
"preset": "conventionalcommits",
"presetConfig": {
"types": [
{ "type": "feat", "section": "Features", "hidden": false },
{ "type": "fix", "section": "Bug Fixes", "hidden": false },
{ "type": "perf", "section": "Performance Improvements", "hidden": false },
{ "type": "revert", "section": "Reverts", "hidden": false },
{ "type": "docs", "section": "Documentation", "hidden": false },
{ "type": "style", "section": "Styles", "hidden": false },
{ "type": "chore", "section": "Miscellaneous Chores", "hidden": false },
{ "type": "refactor", "section": "Code Refactoring", "hidden": false },
{ "type": "test", "section": "Tests", "hidden": false },
{ "type": "build", "section": "Build System", "hidden": false },
{ "type": "ci", "section": "Continuous Integration", "hidden": false }
]
}
}],
"@semantic-release/github",
"@semantic-release/npm"
]
}

View File

@@ -13,10 +13,9 @@ Please raise any significant new functionality or breaking change an issue for d
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.
### Pull Requests
* The latest changes are always in `canary`, so please make your Pull Request against that branch.
* The latest changes are always in `main`, so please make your Pull Request against that branch.
* Pull Requests should be raised for any change
* Pull Requests need approval of a [core contributor](https://next-auth.js.org/contributors#core-team) before merging
* Rebasing in Pull Requests is preferred to keep a clean commit history (see below)
* Run `npm run lint:fix` before committing to make resolving conflicts easier (VSCode users, check out [this extension](https://marketplace.visualstudio.com/items?itemName=chenxsan.vscode-standardjs) to fix lint issues in development)
* We encourage you to test your changes, and if you have the opportunity, please make those tests part of the Pull Request
* If you add new functionality, please provide the corresponding documentation as well and make it part of the Pull Request
@@ -89,7 +88,7 @@ We use [semantic-release](https://github.com/semantic-release/semantic-release)
When accepting Pull Requests, make sure the following:
* Use "Squash and merge"
* Make sure you merge contributor PRs into `canary`
* Make sure you merge contributor PRs into `main`
* Rewrite the commit message to conform to the `Conventional Commits` style. Check the "Recommended Scopes" section for further advice.
* Optionally link issues the PR will resolve (You can add "close" in front of the issue numbers to close the issues automatically, when the PR is merged. `semantic-release` will also comment back to connected issues and PRs, notifying the users that a feature is added/bug fixed, etc.)

3
FUNDING.yml Normal file
View File

@@ -0,0 +1,3 @@
# https://docs.github.com/en/github/administering-a-repository/displaying-a-sponsor-button-in-your-repository
github: [balazsorban44]

View File

@@ -7,12 +7,25 @@
Open Source. Full Stack. Own Your Data.
</p>
<p align="center" style="align: center;">
<img src="https://github.com/nextauthjs/next-auth/workflows/Build%20Test/badge.svg" alt="Build Test" />
<img src="https://github.com/nextauthjs/next-auth/workflows/Integration%20Test/badge.svg" alt="Integration Test" />
<img src="https://img.shields.io/bundlephobia/minzip/next-auth" alt="Bundle Size"/>
<img src="https://img.shields.io/npm/dm/next-auth" alt="Downloads" />
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth" alt="Github Stars" />
<img src="https://img.shields.io/github/v/release/nextauthjs/next-auth?include_prereleases" alt="Github Release" />
<a href="https://github.com/nextauthjs/next-auth/actions?query=workflow%3ARelease">
<img src="https://github.com/nextauthjs/next-auth/workflows/Release/badge.svg" alt="Release" />
</a>
<a href="https://github.com/nextauthjs/next-auth/actions?query=workflow%3A%22Integration+Test%22">
<img src="https://github.com/nextauthjs/next-auth/workflows/Integration%20Test/badge.svg" alt="Integration Test" />
</a>
<a href="https://bundlephobia.com/result?p=next-auth">
<img src="https://img.shields.io/bundlephobia/minzip/next-auth" alt="Bundle Size"/>
</a>
<a href="https://www.npmtrends.com/next-auth">
<img src="https://img.shields.io/npm/dm/next-auth" alt="Downloads" />
</a>
<a href="https://github.com/nextauthjs/next-auth/stargazers">
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth" alt="Github Stars" />
</a>
<a href="https://www.npmjs.com/package/next-auth">
<img src="https://img.shields.io/github/v/release/nextauthjs/next-auth" alt="Github Stable Release" />
</a>
<img src="https://img.shields.io/github/v/release/nextauthjs/next-auth?include_prereleases" alt="Github Prelease" />
</p>
</p>

View File

@@ -5,11 +5,14 @@ export default function AccessDenied () {
<>
<h1>Access Denied</h1>
<p>
<a href="/api/auth/signin"
onClick={(e) => {
e.preventDefault()
signIn()
}}>You must be signed in to view this page</a>
<a
href='/api/auth/signin'
onClick={(e) => {
e.preventDefault()
signIn()
}}
>You must be signed in to view this page
</a>
</p>
</>
)

View File

@@ -1,6 +1,5 @@
import Link from 'next/link'
import { signIn, signOut, useSession } from 'next-auth/client'
import * as client from 'next-auth/client'
import styles from './header.module.css'
// The approach used in this component shows how to built a sign in and sign out
@@ -26,7 +25,7 @@ export default function Header () {
You are not signed in
</span>
<a
href="/api/auth/signin"
href='/api/auth/signin'
className={styles.buttonPrimary}
onClick={(e) => {
e.preventDefault()
@@ -51,7 +50,7 @@ export default function Header () {
<strong>{session.user.email || session.user.name}</strong>
</span>
<a
href="/api/auth/signout"
href='/api/auth/signout'
className={styles.button}
onClick={(e) => {
e.preventDefault()
@@ -96,6 +95,11 @@ export default function Header () {
<a>API</a>
</Link>
</li>
<li className={styles.navItem}>
<Link href='/credentials'>
<a>Credentials</a>
</Link>
</li>
</ul>
</nav>
</header>

View File

@@ -1,12 +0,0 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"next-auth": ["./src/server"],
"next-auth/adapters": ["./src/adapters"],
"next-auth/client": ["./src/client"],
"next-auth/jwt": ["./src/lib/jwt"],
"next-auth/providers": ["./src/providers"]
}
}
}

2
next-env.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
/// <reference types="next" />
/// <reference types="next/types/global" />

859
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -29,8 +29,8 @@
"prepublishOnly": "npm run build",
"publish:beta": "npm publish --tag beta",
"publish:canary": "npm publish --tag canary",
"lint": "standard",
"lint:fix": "standard --fix"
"lint": "ts-standard",
"lint:fix": "ts-standard --fix"
},
"files": [
"dist",
@@ -64,21 +64,24 @@
"mysql": "^2.18.1",
"mssql": "^6.2.1",
"pg": "^8.2.1",
"@prisma/client": "^2.12.0"
"@prisma/client": "^2.16.1"
},
"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.9.6",
"@babel/preset-env": "^7.9.6",
"@prisma/client": "^2.16.1",
"@semantic-release/commit-analyzer": "^8.0.1",
"@semantic-release/github": "^7.2.0",
"@semantic-release/npm": "7.0.8",
"@semantic-release/release-notes-generator": "^9.0.1",
"@types/react": "^17.0.0",
"autoprefixer": "^9.7.6",
"babel-preset-preact": "^2.0.0",
"conventional-changelog-conventionalcommits": "4.4.0",
"cssnano": "^4.1.10",
"dotenv": "^8.2.0",
"eslint": "^7.19.0",
"mocha": "^8.1.3",
"mongodb": "^3.5.9",
"mssql": "^6.2.1",
@@ -87,18 +90,29 @@
"pg": "^8.2.1",
"postcss-cli": "^7.1.1",
"postcss-nested": "^4.2.1",
"prisma": "^2.16.1",
"puppeteer": "^5.2.1",
"puppeteer-extra": "^3.1.15",
"puppeteer-extra-plugin-stealth": "^2.6.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"standard": "^16.0.3"
"ts-standard": "^10.0.0",
"typescript": "^4.1.3"
},
"standard": {
"ts-standard": {
"project": "./tsconfig.json",
"ignore": [
"test/",
"pages/",
"components/"
"next-env.d.ts"
],
"globals": [
"fetch"
]
}
},
"funding": [
{
"type" : "github",
"url" : "https://github.com/sponsors/balazsorban44"
}
]
}

View File

@@ -8,10 +8,10 @@ export default function Page () {
<p><em>You must be signed in to see responses.</em></p>
<h2>Session</h2>
<p>/api/examples/session</p>
<iframe src="/api/examples/session"/>
<iframe src='/api/examples/session' />
<h2>JSON Web Token</h2>
<p>/api/examples/jwt</p>
<iframe src="/api/examples/jwt"/>
<iframe src='/api/examples/jwt' />
</Layout>
)
}
}

View File

@@ -1,92 +1,61 @@
import NextAuth from "next-auth"
import Providers from "next-auth/providers"
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
// import Adapters from 'next-auth/adapters'
// import { PrismaClient } from '@prisma/client'
// const prisma = new PrismaClient()
export default NextAuth({
// https://next-auth.js.org/configuration/providers
providers: [
Providers.Email({
server: process.env.EMAIL_SERVER,
from: process.env.EMAIL_FROM
}),
Providers.GitHub({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
clientSecret: process.env.GITHUB_SECRET
}),
Providers.Auth0({
clientId: process.env.AUTH0_ID,
clientSecret: process.env.AUTH0_SECRET,
domain: process.env.AUTH0_DOMAIN,
protection: "pkce"
protection: 'pkce'
}),
Providers.Twitter({
clientId: process.env.TWITTER_ID,
clientSecret: process.env.TWITTER_SECRET,
clientSecret: process.env.TWITTER_SECRET
}),
Providers.Credentials({
name: 'Credentials',
credentials: {
password: { label: 'Password', type: 'password' }
},
async authorize (credentials) {
if (credentials.password === 'password') {
return {
id: 1,
name: 'Fill Murray',
email: 'bill@fillmurray.com',
image: 'https://www.fillmurray.com/64/64'
}
}
return null
}
})
],
// Database optional. MySQL, Maria DB, Postgres and MongoDB are supported.
// https://next-auth.js.org/configuration/databases
//
// Notes:
// * You must to install an appropriate node_module for your database
// * The Email provider requires a database (OAuth providers do not)
// The secret should be set to a reasonably long random string.
// It is used to sign cookies and to sign and encrypt JSON Web Tokens, unless
// a separate secret is defined explicitly for encrypting the JWT.
session: {
// Use JSON Web Tokens for session instead of database sessions.
// This option can be used with or without a database for users/accounts.
// Note: `jwt` is automatically set to `true` if no database is specified.
jwt: true,
// Seconds - How long until an idle session expires and is no longer valid.
// maxAge: 30 * 24 * 60 * 60, // 30 days
// Seconds - Throttle how frequently to write to database to extend a session.
// Use it to limit write operations. Set to 0 to always update the database.
// Note: This option is ignored if using JSON Web Tokens
// updateAge: 24 * 60 * 60, // 24 hours
},
// JSON Web tokens are only used for sessions if the `jwt: true` session
// option is set - or by default if no database is specified.
// https://next-auth.js.org/configuration/options#jwt
jwt: {
encryption: true,
secret: process.env.SECRET,
// A secret to use for key generation (you should set this explicitly)
// secret: 'INp8IvdIyeMcoGAgFGoA61DdBglwwSqnXJZkgz8PSnw',
// Set to true to use encryption (default: false)
// encryption: true,
// You can define your own encode/decode functions for signing and encryption
// if you want to override the default behaviour.
// encode: async ({ secret, token, maxAge }) => {},
// decode: async ({ secret, token, maxAge }) => {},
secret: process.env.SECRET
},
// You can define custom pages to override the built-in pages.
// The routes shown here are the default URLs that will be used when a custom
// pages is not specified for that route.
// https://next-auth.js.org/configuration/pages
pages: {
// signIn: '/api/auth/signin', // Displays signin buttons
// signOut: '/api/auth/signout', // Displays form with sign out button
// error: '/api/auth/error', // Error code passed in query string as ?error=
// verifyRequest: '/api/auth/verify-request', // Used for check email page
// newUser: null // If set, new users will be directed here on first sign in
},
// Callbacks are asynchronous functions you can use to control what happens
// when an action is performed.
// https://next-auth.js.org/configuration/callbacks
callbacks: {
// signIn: async (user, account, profile) => { return Promise.resolve(true) },
// redirect: async (url, baseUrl) => { return Promise.resolve(baseUrl) },
// session: async (session, user) => { return Promise.resolve(session) },
// jwt: async (token, user, account, profile, isNewUser) => { return Promise.resolve(token) }
},
// Events are useful for logging
// https://next-auth.js.org/configuration/events
events: {},
// Enable debug messages in the console if you are having problems
debug: false,
theme: 'auto'
// Default Database Adapter (TypeORM)
// database: process.env.DATABASE_URL
// Prisma Database Adapter
// To configure this app to use the schema in `prisma/schema.prisma` run:
// npx prisma generate
// npx prisma migrate dev --preview-feature
// adapter: Adapters.Prisma.Adapter({ prisma })
})

View File

@@ -1,9 +1,9 @@
// This is an example of how to read a JSON Web Token from an API route
import jwt from "next-auth/jwt"
import jwt from 'next-auth/jwt'
const secret = process.env.SECRET
export default async (req, res) => {
const token = await jwt.getToken({ req, secret, encryption: true })
const token = await jwt.getToken({ req, secret })
res.send(JSON.stringify(token, null, 2))
}

View File

@@ -9,4 +9,4 @@ export default async (req, res) => {
} else {
res.send({ error: 'You must be sign in to view the protected content on this page.' })
}
}
}

View File

@@ -4,4 +4,4 @@ import { getSession } from 'next-auth/client'
export default async (req, res) => {
const session = await getSession({ req })
res.send(JSON.stringify(session, null, 2))
}
}

View File

@@ -19,4 +19,4 @@ export default function Page () {
</p>
</Layout>
)
}
}

52
pages/credentials.js Normal file
View File

@@ -0,0 +1,52 @@
import * as React from 'react'
import { signIn, signOut, useSession } from 'next-auth/client'
import Layout from 'components/layout'
export default function Page () {
const [response, setResponse] = React.useState(null)
const handleLogin = (options) => async () => {
if (options.redirect) {
return signIn('credentials', options)
}
const response = await signIn('credentials', options)
setResponse(response)
}
const handleLogout = (options) => async () => {
if (options.redirect) {
return signOut(options)
}
const response = await signOut(options)
setResponse(response)
}
const [session] = useSession()
if (session) {
return (
<Layout>
<h1>Test different flows for Credentials logout</h1>
<span className='spacing'>Default:</span>
<button onClick={handleLogout({ redirect: true })}>Logout</button><br />
<span className='spacing'>No redirect:</span>
<button onClick={handleLogout({ redirect: false })}>Logout</button><br />
<p>Response:</p>
<pre style={{ background: '#eee', padding: 16 }}>{JSON.stringify(response, null, 2)}</pre>
</Layout>
)
}
return (
<Layout>
<h1>Test different flows for Credentials login</h1>
<span className='spacing'>Default:</span>
<button onClick={handleLogin({ redirect: true, password: 'password' })}>Login</button><br />
<span className='spacing'>No redirect:</span>
<button onClick={handleLogin({ redirect: false, password: 'password' })}>Login</button><br />
<span className='spacing'>No redirect, wrong password:</span>
<button onClick={handleLogin({ redirect: false, password: '' })}>Login</button>
<p>Response:</p>
<pre style={{ background: '#eee', padding: 16 }}>{JSON.stringify(response, null, 2)}</pre>
</Layout>
)
}

View File

@@ -4,7 +4,7 @@ export default function Page () {
return (
<Layout>
<p>
This is an example site to demonstrate how to use <a href={`https://next-auth.js.org`}>NextAuth.js</a> for authentication.
This is an example site to demonstrate how to use <a href='https://next-auth.js.org'>NextAuth.js</a> for authentication.
</p>
<h2>Terms of Service</h2>
<p>
@@ -27,4 +27,4 @@ export default function Page () {
</p>
</Layout>
)
}
}

View File

@@ -5,7 +5,7 @@ import AccessDenied from '../components/access-denied'
export default function Page ({ content, session }) {
// If no session exists, display access denied message
if (!session) { return <Layout><AccessDenied/></Layout> }
if (!session) { return <Layout><AccessDenied /></Layout> }
// If session exists, display content
return (
@@ -16,7 +16,7 @@ export default function Page ({ content, session }) {
)
}
export async function getServerSideProps(context) {
export async function getServerSideProps (context) {
const session = await getSession(context)
let content = null

View File

@@ -4,24 +4,24 @@ import Layout from '../components/layout'
import AccessDenied from '../components/access-denied'
export default function Page () {
const [ session, loading ] = useSession()
const [ content , setContent ] = useState()
const [session, loading] = useSession()
const [content, setContent] = useState()
// Fetch content from protected route
useEffect(()=>{
useEffect(() => {
const fetchData = async () => {
const res = await fetch('/api/examples/protected')
const json = await res.json()
if (json.content) { setContent(json.content) }
}
fetchData()
},[session])
}, [session])
// When rendering client side don't display anything until loading is complete
if (typeof window !== 'undefined' && loading) return null
// If no session exists, display access denied message
if (!session) { return <Layout><AccessDenied/></Layout> }
if (!session) { return <Layout><AccessDenied /></Layout> }
// If session exists, display content
return (
@@ -30,4 +30,4 @@ export default function Page () {
<p><strong>{content}</strong></p>
</Layout>
)
}
}

View File

@@ -1,4 +1,4 @@
import { useSession, getSession } from 'next-auth/client'
import { getSession } from 'next-auth/client'
import Layout from '../components/layout'
export default function Page () {
@@ -6,7 +6,6 @@ export default function Page () {
// populated on render without needing to go through a loading stage.
// This is possible because of the shared context configured in `_app.js` that
// is used by `useSession()`.
const [ session, loading ] = useSession()
return (
<Layout>
@@ -29,7 +28,7 @@ export default function Page () {
}
// Export the `session` prop to use sessions with Server Side Rendering
export async function getServerSideProps(context) {
export async function getServerSideProps (context) {
return {
props: {
session: await getSession(context)

63
prisma/schema.prisma Normal file
View File

@@ -0,0 +1,63 @@
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Account {
id Int @default(autoincrement()) @id
compoundId String @unique @map(name: "compound_id")
userId Int @map(name: "user_id")
providerType String @map(name: "provider_type")
providerId String @map(name: "provider_id")
providerAccountId String @map(name: "provider_account_id")
refreshToken String? @map(name: "refresh_token")
accessToken String? @map(name: "access_token")
accessTokenExpires DateTime? @map(name: "access_token_expires")
createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @default(now()) @map(name: "updated_at")
@@index([providerAccountId], name: "providerAccountId")
@@index([providerId], name: "providerId")
@@index([userId], name: "userId")
@@map(name: "accounts")
}
model Session {
id Int @default(autoincrement()) @id
userId Int @map(name: "user_id")
expires DateTime
sessionToken String @unique @map(name: "session_token")
accessToken String @unique @map(name: "access_token")
createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @default(now()) @map(name: "updated_at")
@@map(name: "sessions")
}
model User {
id Int @default(autoincrement()) @id
name String?
email String? @unique
emailVerified DateTime? @map(name: "email_verified")
image String?
createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @default(now()) @map(name: "updated_at")
@@map(name: "users")
}
model VerificationRequest {
id Int @default(autoincrement()) @id
identifier String
token String @unique
expires DateTime
createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @default(now()) @map(name: "updated_at")
@@map(name: "verification_requests")
}

7
release.config.js Normal file
View File

@@ -0,0 +1,7 @@
module.exports = {
branches: [
'+([0-9])?(.{+([0-9]),x}).x',
'main',
{ name: 'next', prerelease: true }
]
}

View File

@@ -1,84 +1,83 @@
const Adapter = (config, options = {}) => {
async function getAdapter (appOptions) {
const { logger } = appOptions
// Display debug output if debug option enabled
function _debug (...args) {
if (appOptions.debug) {
console.log('[next-auth][debug]', ...args)
}
function debug (debugCode, ...args) {
logger.debug(`ADAPTER_${debugCode}`, ...args)
}
async function createUser (profile) {
_debug('createUser', profile)
debug('createUser', profile)
return null
}
async function getUser (id) {
_debug('getUser', id)
debug('getUser', id)
return null
}
async function getUserByEmail (email) {
_debug('getUserByEmail', email)
debug('getUserByEmail', email)
return null
}
async function getUserByProviderAccountId (providerId, providerAccountId) {
_debug('getUserByProviderAccountId', providerId, providerAccountId)
debug('getUserByProviderAccountId', providerId, providerAccountId)
return null
}
async function updateUser (user) {
_debug('updateUser', user)
debug('updateUser', user)
return null
}
async function deleteUser (userId) {
_debug('deleteUser', userId)
debug('deleteUser', userId)
return null
}
async function linkAccount (userId, providerId, providerType, providerAccountId, refreshToken, accessToken, accessTokenExpires) {
_debug('linkAccount', userId, providerId, providerType, providerAccountId, refreshToken, accessToken, accessTokenExpires)
debug('linkAccount', userId, providerId, providerType, providerAccountId, refreshToken, accessToken, accessTokenExpires)
return null
}
async function unlinkAccount (userId, providerId, providerAccountId) {
_debug('unlinkAccount', userId, providerId, providerAccountId)
debug('unlinkAccount', userId, providerId, providerAccountId)
return null
}
async function createSession (user) {
_debug('createSession', user)
debug('createSession', user)
return null
}
async function getSession (sessionToken) {
_debug('getSession', sessionToken)
debug('getSession', sessionToken)
return null
}
async function updateSession (session, force) {
_debug('updateSession', session)
debug('updateSession', session)
return null
}
async function deleteSession (sessionToken) {
_debug('deleteSession', sessionToken)
debug('deleteSession', sessionToken)
return null
}
async function createVerificationRequest (identifier, url, token, secret, provider) {
_debug('createVerificationRequest', identifier)
debug('createVerificationRequest', identifier)
return null
}
async function getVerificationRequest (identifier, token, secret, provider) {
_debug('getVerificationRequest', identifier, token)
debug('getVerificationRequest', identifier, token)
return null
}
async function deleteVerificationRequest (identifier, token, secret, provider) {
_debug('deleteVerification', identifier, token)
debug('deleteVerification', identifier, token)
return null
}

View File

@@ -1,7 +1,6 @@
import { createHash, randomBytes } from 'crypto'
import { CreateUserError } from '../../lib/errors'
import logger from '../../lib/logger'
const Adapter = (config) => {
const {
@@ -21,6 +20,7 @@ const Adapter = (config) => {
}
async function getAdapter (appOptions) {
const { logger } = appOptions
function debug (debugCode, ...args) {
logger.debug(`PRISMA_${debugCode}`, ...args)
}
@@ -280,11 +280,15 @@ const Adapter = (config) => {
// Hash token provided with secret before trying to match it with database
// @TODO Use bcrypt instead of salted SHA-256 hash for token
const hashedToken = createHash('sha256').update(`${token}${secret}`).digest('hex')
const verificationRequest = await prisma[VerificationRequest].findUnique({ where: { token: hashedToken } })
const verificationRequest = await prisma[VerificationRequest].findFirst({
where: {
identifier,
token: hashedToken
}
})
if (verificationRequest && verificationRequest.expires && new Date() > verificationRequest.expires) {
// Delete verification entry so it cannot be used again
await prisma[VerificationRequest].delete({ where: { token: hashedToken } })
await prisma[VerificationRequest].deleteMany({ where: { identifier, token: hashedToken } })
return null
}
@@ -300,7 +304,7 @@ const Adapter = (config) => {
try {
// Delete verification entry so it cannot be used again
const hashedToken = createHash('sha256').update(`${token}${secret}`).digest('hex')
await prisma[VerificationRequest].delete({ where: { token: hashedToken } })
await prisma[VerificationRequest].deleteMany({ where: { identifier, token: hashedToken } })
} catch (error) {
logger.error('DELETE_VERIFICATION_REQUEST_ERROR', error)
return Promise.reject(new Error('DELETE_VERIFICATION_REQUEST_ERROR', error))

View File

@@ -6,7 +6,7 @@ import { CreateUserError } from '../../lib/errors'
import adapterConfig from './lib/config'
import adapterTransform from './lib/transform'
import Models from './models'
import logger from '../../lib/logger'
import { updateConnectionEntities } from './lib/utils'
const Adapter = (typeOrmConfig, options = {}) => {
@@ -41,6 +41,12 @@ const Adapter = (typeOrmConfig, options = {}) => {
let connection = null
async function getAdapter (appOptions) {
const { logger } = appOptions
// Display debug output if debug option enabled
function debug (debugCode, ...args) {
logger.debug(`TYPEORM_${debugCode}`, ...args)
}
// Helper function to reuse / restablish connections
// (useful if they drop when after being idle)
async function _connect () {
@@ -77,12 +83,6 @@ const Adapter = (typeOrmConfig, options = {}) => {
// https://github.com/typeorm/typeorm/blob/master/docs/entity-manager-api.md
const { manager } = connection
// Display debug output if debug option enabled
// @TODO Refactor logger so is passed in appOptions
function debug (debugCode, ...args) {
logger.debug(`TYPEORM_${debugCode}`, ...args)
}
// The models are primarily designed for ANSI SQL database, but some
// flexiblity is required in the adapter to support non-SQL databases such
// as MongoDB which have different pragmas.
@@ -331,7 +331,7 @@ const Adapter = (typeOrmConfig, options = {}) => {
if (verificationRequest && verificationRequest.expires && new Date() > new Date(verificationRequest.expires)) {
// Delete verification entry so it cannot be used again
await manager.delete(VerificationRequest, { token: hashedToken })
await manager.delete(VerificationRequest, { identifier, token: hashedToken })
return null
}
@@ -347,7 +347,7 @@ const Adapter = (typeOrmConfig, options = {}) => {
try {
// Delete verification entry so it cannot be used again
const hashedToken = createHash('sha256').update(`${token}${secret}`).digest('hex')
await manager.delete(VerificationRequest, { token: hashedToken })
await manager.delete(VerificationRequest, { identifier, token: hashedToken })
} catch (error) {
logger.error('DELETE_VERIFICATION_REQUEST_ERROR', error)
return Promise.reject(new Error('DELETE_VERIFICATION_REQUEST_ERROR', error))

View File

@@ -10,9 +10,8 @@
//
// We use HTTP POST requests with CSRF Tokens to protect against CSRF attacks.
/* global fetch:false */
import { useState, useEffect, useContext, createContext, createElement } from 'react'
import logger from '../lib/logger'
import _logger, { proxyLogger } from '../lib/logger'
import parseUrl from '../lib/parse-url'
// This behaviour mirrors the default behaviour for getting the site name that
@@ -38,6 +37,8 @@ const __NEXTAUTH = {
_getSession: () => {}
}
const logger = proxyLogger(_logger, __NEXTAUTH.basePath)
// Add event listners on load
if (typeof window !== 'undefined') {
if (__NEXTAUTH._eventListenersAdded === false) {
@@ -115,12 +116,10 @@ const setOptions = ({
}
// Universal method (client + server)
export const getSession = async ({ req, ctx, triggerEvent = true } = {}) => {
// If passed 'appContext' via getInitialProps() in _app.js then get the req
// object from ctx and use that for the req value to allow getSession() to
// work seemlessly in getInitialProps() on server side pages *and* in _app.js.
if (!req && ctx && ctx.req) { req = ctx.req }
// If passed 'appContext' via getInitialProps() in _app.js then get the req
// object from ctx and use that for the req value to allow getSession() to
// work seemlessly in getInitialProps() on server side pages *and* in _app.js.
export async function getSession ({ ctx, req = ctx?.req, triggerEvent = true } = {}) {
const baseUrl = _apiBaseUrl()
const fetchOptions = req ? { headers: { cookie: req.headers.cookie } } : {}
const session = await _fetchData(`${baseUrl}/session`, fetchOptions)
@@ -131,12 +130,10 @@ export const getSession = async ({ req, ctx, triggerEvent = true } = {}) => {
}
// Universal method (client + server)
const getCsrfToken = async ({ req, ctx } = {}) => {
// If passed 'appContext' via getInitialProps() in _app.js then get the req
// object from ctx and use that for the req value to allow getCsrfToken() to
// work seemlessly in getInitialProps() on server side pages *and* in _app.js.
if (!req && ctx && ctx.req) { req = ctx.req }
// If passed 'appContext' via getInitialProps() in _app.js then get the req
// object from ctx and use that for the req value to allow getCsrfToken() to
// work seemlessly in getInitialProps() on server side pages *and* in _app.js.
async function getCsrfToken ({ ctx, req = ctx?.req } = {}) {
const baseUrl = _apiBaseUrl()
const fetchOptions = req ? { headers: { cookie: req.headers.cookie } } : {}
const data = await _fetchData(`${baseUrl}/csrf`, fetchOptions)
@@ -233,62 +230,116 @@ const _useSessionHook = (session) => {
return [data, loading]
}
// Client side method
export const signIn = async (provider, args = {}, authorizationParams = {}) => {
/**
* Client-side method to initiate a signin flow
* or send the user to the signin page listing all possible providers.
* (Automatically adds the CSRF token to the request)
* @see https://next-auth.js.org/getting-started/client#signin
* @param {string} [provider]
* @param {SignInOptions} [options]
* @param {object} [authorizationParams]
* @return {Promise<SignInResponse | undefined>}
* @typedef {{callbackUrl?: string; redirect?: boolean}} SignInOptions
* @typedef {{error: string | null; status: number; ok: boolean}} SignInResponse
*/
export async function signIn (provider, options = {}, authorizationParams = {}) {
const {
callbackUrl = window.location,
redirect = true
} = options
const baseUrl = _apiBaseUrl()
const callbackUrl = args?.callbackUrl ?? window.location
const providers = await getProviders()
// Redirect to sign in page if no valid provider specified
if (!(provider in providers)) {
// If Provider not recognized, redirect to sign in page
window.location = `${baseUrl}/signin?callbackUrl=${encodeURIComponent(callbackUrl)}`
} else {
const signInUrl = (providers[provider].type === 'credentials')
? `${baseUrl}/callback/${provider}`
: `${baseUrl}/signin/${provider}`
return
}
const isCredentials = providers[provider].type === 'credentials'
const signInUrl = isCredentials
? `${baseUrl}/callback/${provider}`
: `${baseUrl}/signin/${provider}`
// If is any other provider type, POST to provider URL with CSRF Token,
// callback URL and any other parameters supplied.
const fetchOptions = {
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: _encodedForm({
...args,
csrfToken: await getCsrfToken(),
callbackUrl: callbackUrl,
json: true
})
}
const _signInUrl = `${signInUrl}?${_encodedForm(authorizationParams)}`
const res = await fetch(_signInUrl, fetchOptions)
const data = await res.json()
window.location = data.url ?? callbackUrl
// If is any other provider type, POST to provider URL with CSRF Token,
// callback URL and any other parameters supplied.
const fetchOptions = {
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
...options,
csrfToken: await getCsrfToken(),
callbackUrl,
json: true
})
}
const _signInUrl = `${signInUrl}?${new URLSearchParams(authorizationParams)}`
const res = await fetch(_signInUrl, fetchOptions)
const data = await res.json()
if (redirect || !isCredentials) {
const url = data.url ?? callbackUrl
window.location = url
// If url contains a hash, the browser does not reload the page. We reload manually
if (url.includes('#')) window.location.reload()
return
}
const error = new URL(data.url).searchParams.get('error')
if (res.ok) {
await __NEXTAUTH._getSession({ event: 'storage' })
}
return {
error,
status: res.status,
ok: res.ok,
url: error ? null : data.url
}
}
// Client side method
export const signOut = async (args = {}) => {
const callbackUrl = args.callbackUrl ?? window.location
/**
* Signs the user out, by removing the session cookie.
* (Automatically adds the CSRF token to the request)
* @param {SignOutOptions} [options]
* @returns {Promise<{url?: string} | undefined>}
* @typedef {{callbackUrl?: string; redirect?: boolean;}} SignOutOptions
*/
export async function signOut (options = {}) {
const {
callbackUrl = window.location,
redirect = true
} = options
const baseUrl = _apiBaseUrl()
const fetchOptions = {
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: _encodedForm({
body: new URLSearchParams({
csrfToken: await getCsrfToken(),
callbackUrl: callbackUrl,
callbackUrl,
json: true
})
}
const res = await fetch(`${baseUrl}/signout`, fetchOptions)
const data = await res.json()
_sendMessage({ event: 'session', data: { trigger: 'signout' } })
window.location = data.url ?? callbackUrl
if (redirect) {
const url = data.url ?? callbackUrl
window.location = url
// If url contains a hash, the browser does not reload the page. We reload manually
if (url.includes('#')) window.location.reload()
return
}
await __NEXTAUTH._getSession({ event: 'storage' })
return data
}
// Provider to wrap the app in to make session data available globally
@@ -321,12 +372,6 @@ const _apiBaseUrl = () => {
}
}
const _encodedForm = (formData) => {
return Object.keys(formData).map((key) => {
return encodeURIComponent(key) + '=' + encodeURIComponent(formData[key])
}).join('&')
}
const _sendMessage = (message) => {
if (typeof localStorage !== 'undefined') {
const timestamp = Math.floor(new Date().getTime() / 1000)

View File

@@ -3,6 +3,7 @@
--border-radius: .3rem;
--color-error: #c94b4b;
--color-info: #157efb;
--color-info-text: #fff;
}
.__next-auth-theme-auto,
@@ -23,7 +24,6 @@
--color-control-border: #555;
--color-button-active-background: #060606;
--color-button-active-border: #666;
--color-seperator: #444;
}
@@ -80,6 +80,7 @@ input[type] {
font-size: 1rem;
border-radius: var(--border-radius);
box-shadow: inset 0 .1rem .2rem rgba(0, 0, 0, .2);
color: var(--color-text);
&:focus {
box-shadow: none;
@@ -202,13 +203,13 @@ a.site {
font-weight: 500;
border-radius: 0.3rem;
background: var(--color-info);
color: var(--color-text);
p {
text-align: left;
padding: 0.5rem 1rem;
font-size: 0.9rem;
line-height: 1.2rem;
color: var(--color-info-text);
}
}

5
src/lib/logger.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
export interface LoggerInstance {
warn: (code?: string, ...message: unknown[]) => void
error: (code?: string, ...message: unknown[]) => void
debug: (code?: string, ...message: unknown[]) => void
}

View File

@@ -1,4 +1,5 @@
const logger = {
/** @type {import("./logger").LoggerInstance} */
const _logger = {
error (code, ...message) {
console.error(
`[next-auth][error][${code.toLowerCase()}]`,
@@ -22,4 +23,60 @@ const logger = {
}
}
export default logger
/**
* Override the built-in logger.
* Any `undefined` level will use the default logger.
* @param {Partial<import("./logger").LoggerInstance>} newLogger
*/
export function setLogger (newLogger = {}) {
if (newLogger.error) _logger.error = newLogger.error
if (newLogger.warn) _logger.warn = newLogger.warn
if (newLogger.debug) _logger.debug = newLogger.debug
}
export default _logger
/**
* Serializes client-side log messages and sends them to the server
* @param {import("./logger").LoggerInstance} logger
* @param {string} basePath
* @return {import("./logger").LoggerInstance}
*/
export function proxyLogger (logger = _logger, basePath) {
try {
if (typeof window === 'undefined') {
return logger
}
const clientLogger = {}
for (const level in logger) {
clientLogger[level] = (code, ...message) => {
_logger[level](code, ...message) // Log on client as usual
const url = `${basePath}/_log`
const body = new URLSearchParams({
level,
code,
message: JSON.stringify(message.map(m => {
if (m instanceof Error) {
// Serializing errors: https://iaincollins.medium.com/error-handling-in-javascript-a6172ccdf9af
return { name: m.name, message: m.message, stack: m.stack }
}
return m
}))
})
if (navigator.sendBeacon) {
return navigator.sendBeacon(url, body)
}
return fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body
})
}
}
return clientLogger
} catch {
return _logger
}
}

View File

@@ -0,0 +1,21 @@
export default (options) => {
return {
id: 'eveonline',
name: 'EVE Online',
type: 'oauth',
version: '2.0',
params: { grant_type: 'authorization_code' },
accessTokenUrl: 'https://login.eveonline.com/oauth/token',
authorizationUrl: 'https://login.eveonline.com/oauth/authorize?response_type=code',
profileUrl: 'https://login.eveonline.com/oauth/verify',
profile: (profile) => {
return {
id: profile.CharacterID,
name: profile.CharacterName,
image: `https://image.eveonline.com/Character/${profile.CharacterID}_128.jpg`,
email: null
}
},
...options
}
}

View File

@@ -10,6 +10,7 @@ import Cognito from './cognito'
import Credentials from './credentials'
import Discord from './discord'
import Email from './email'
import EVEOnline from './eveonline'
import Facebook from './facebook'
import Foursquare from './foursquare'
import FusionAuth from './fusionauth'
@@ -46,6 +47,7 @@ export default {
Credentials,
Discord,
Email,
EVEOnline,
Facebook,
Foursquare,
FusionAuth,

View File

@@ -3,7 +3,7 @@ export default (options) => {
return {
id: 'vk',
name: 'vk.com',
name: 'VK',
type: 'oauth',
version: '2.0',
scope: 'email',

94
src/server/index.d.ts vendored Normal file
View File

@@ -0,0 +1,94 @@
import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
import { LoggerInstance } from 'src/lib/logger'
import { CallbacksOptions } from './lib/callbacks'
import { CookiesOptions } from './lib/cookie'
import { EventsOptions } from './lib/events'
export interface Provider {
id: string
name: string
type: string
version: string
params: Record<string, unknown>
scope: string
accessTokenUrl: string
authorizationUrl: string
profileUrl?: string
grant_type?: string
profile?: (profile: any) => Promise<any>
}
/** @docs https://next-auth.js.org/configuration/options */
export interface NextAuthOptions {
/** @docs https://next-auth.js.org/configuration/options#theme */
theme?: 'auto' | 'dark' | 'light'
/** @docs https://next-auth.js.org/configuration/options#providers */
providers: Provider[]
/** @docs https://next-auth.js.org/configuration/options#database */
database?: any
/** @docs https://next-auth.js.org/configuration/options#secret */
secret?: any
/** @docs https://next-auth.js.org/configuration/options#session */
session?: any
/** @docs https://next-auth.js.org/configuration/options#jwt */
jwt?: any
/** @docs https://next-auth.js.org/configuration/options#pages */
pages?: {
signIn?: string
signOut?: string
/** Error code passed in query string as ?error= */
error?: string
verifyRequest?: string
/** If set, new users will be directed here on first sign in */
newUser?: string
}
/**
* Callbacks are asynchronous functions you can use to control what happens when an action is performed.
* Callbacks are extremely powerful, especially in scenarios involving JSON Web Tokens as
* they allow you to implement access controls without a database and
* to integrate with external databases or APIs.
* @docs https://next-auth.js.org/configuration/options#callbacks
*/
callbacks?: CallbacksOptions
/** @docs https://next-auth.js.org/configuration/options#events */
events?: EventsOptions
/** @docs https://next-auth.js.org/configuration/options#adapter */
adapter?: any
/** @docs https://next-auth.js.org/configuration/options#debug */
debug?: boolean
/** @docs https://next-auth.js.org/configuration/options#usesecurecookies */
useSecureCookies?: boolean
/** @docs https://next-auth.js.org/configuration/options#cookies */
cookies?: CookiesOptions
/** @docs https://next-auth.js.org/configuration/options#logger */
logger: LoggerInstance
}
/** Options that are the same both in internal and user provided options. */
export type NextAuthSharedOptions = 'pages' | 'jwt' | 'events' | 'callbacks' | 'cookies' | 'secret' | 'adapter' | 'theme' | 'debug' | 'logger'
export interface NextAuthInternalOptions extends Pick<NextAuthOptions, NextAuthSharedOptions> {
pkce?: {
code_verifier?: string
/**
* Could be `"plain"`, but not recommended.
* We ignore it for now.
* @spec https://tools.ietf.org/html/rfc7636#section-4.2.
*/
code_challenge_method?: 'S256'
}
provider?: Provider
baseUrl?: string
basePath?: string
action?: string
csrfToken?: string
}
export interface NextAuthRequest extends NextApiRequest {
options: NextAuthInternalOptions
}
export interface NextAuthResponse extends NextApiResponse {}
export declare function NextAuthHandler (req: NextAuthRequest, res: NextAuthResponse, options: NextAuthOptions): ReturnType<NextApiHandler>
export declare function NextAuthHandler (options: NextAuthOptions): ReturnType<NextApiHandler>

View File

@@ -1,7 +1,7 @@
import adapters from '../adapters'
import jwt from '../lib/jwt'
import parseUrl from '../lib/parse-url'
import logger from '../lib/logger'
import logger, { setLogger } from '../lib/logger'
import * as cookie from './lib/cookie'
import * as defaultEvents from './lib/default-events'
import * as defaultCallbacks from './lib/default-callbacks'
@@ -21,7 +21,15 @@ if (!process.env.NEXTAUTH_URL) {
logger.warn('NEXTAUTH_URL', 'NEXTAUTH_URL environment variable not set')
}
/**
* @param {import("next").NextApiRequest} req
* @param {import("next").NextApiResponse} res
* @param {import(".").NextAuthOptions} userOptions
*/
async function NextAuthHandler (req, res, userOptions) {
if (userOptions.logger) {
setLogger(userOptions.logger)
}
// If debug enabled, set ENV VAR so that logger logs debug messages
if (userOptions.debug) {
process.env._NEXTAUTH_DEBUG = true
@@ -122,7 +130,8 @@ async function NextAuthHandler (req, res, userOptions) {
...defaultCallbacks,
...userOptions.callbacks
},
pkce: {}
pkce: {},
logger
}
await callbackUrlHandler(req, res)
@@ -215,6 +224,21 @@ async function NextAuthHandler (req, res, userOptions) {
return routes.callback(req, res)
}
break
case '_log':
try {
if (!userOptions.logger) return
const {
code = 'CLIENT_ERROR',
level = 'error',
message = '[]'
} = req.body
logger[level](code, ...JSON.parse(message))
} catch (error) {
// If logging itself failed...
logger.error('LOGGER_ERROR', error)
}
return res.end()
default:
}
}

7
src/server/lib/callbacks.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
export interface CallbacksOptions {
signIn?: (user: any, account: any, profile: any) => Promise<never | string>
jwt?: (token: any, user: any, account: any, profile: any, isNewUser?: boolean) => Promise<any>
session?: (session: any, userOrToken: any) => Promise<any>
redirect?: (url: string, baseUrl: string) => Promise<string>
}

16
src/server/lib/cookie.d.ts vendored Normal file
View File

@@ -0,0 +1,16 @@
export interface CookieOption {
name: string
options: {
httpOnly: boolean
sameSite: string
path?: string
secure: boolean
}
}
export interface CookiesOptions {
sessionToken: CookieOption
callbackUrl: CookieOption
csrfToken: CookieOption
pkceCodeVerifier: CookieOption
}

View File

@@ -110,6 +110,7 @@ function _serialize (name, val, options) {
* For more on prefixes see https://googlechrome.github.io/samples/cookie-prefixes/
*
* @TODO Review cookie settings (names, options)
* @return {import("./cookie").CookiesOptions}
*/
export function defaultCookies (useSecureCookies) {
const cookiePrefix = useSecureCookies ? '__Secure-' : ''

12
src/server/lib/events.d.ts vendored Normal file
View File

@@ -0,0 +1,12 @@
export type EventType=
| 'signIn'
| 'signOut'
| 'createUser'
| 'updateUser'
| 'linkAccount'
| 'session'
| 'error'
export type EventCallback = (message: any) => Promise<void>
export type EventsOptions = Partial<Record<EventType, EventCallback>>

View File

@@ -3,6 +3,7 @@ import oAuthClient from './client'
import logger from '../../../lib/logger'
import { OAuthCallbackError } from '../../../lib/errors'
/** @param {import("../..").NextAuthRequest} req */
export default async function oAuthCallback (req) {
const { provider, pkce } = req.options
const client = oAuthClient(provider)
@@ -89,7 +90,7 @@ export default async function oAuthCallback (req) {
* refresh_token?: string
* id_token?: string
* }
* provider: object
* provider: import("../..").Provider
* user?: object
* }} profileParams
*/

View File

@@ -7,6 +7,7 @@ import { sign as jwtSign } from 'jsonwebtoken'
* @TODO Refactor to remove dependancy on 'oauth' package
* It is already quite monkey patched, we don't use all the features and and it
* would be easier to maintain if all the code was native to next-auth.
* @param {import("../..").Provider} provider
*/
export default function oAuthClient (provider) {
if (provider.version?.startsWith('2.')) {
@@ -86,6 +87,9 @@ export default function oAuthClient (provider) {
/**
* Ported from https://github.com/ciaranj/node-oauth/blob/a7f8a1e21c362eb4ed2039431fb9ac2ae749f26a/lib/oauth2.js
* @param {string} code
* @param {import("../..").Provider} provider
* @param {string | undefined} codeVerifier
*/
async function getOAuth2AccessToken (code, provider, codeVerifier) {
const url = provider.accessTokenUrl
@@ -128,7 +132,7 @@ async function getOAuth2AccessToken (code, provider, codeVerifier) {
headers.Authorization = 'Basic ' + Buffer.from((provider.clientId + ':' + provider.clientSecret)).toString('base64')
}
if ((provider.id === 'okta' || provider.id === 'identity-server4') && !headers.Authorization) {
if (provider.id === 'identity-server4' && !headers.Authorization) {
headers.Authorization = `Bearer ${code}`
}
@@ -184,6 +188,9 @@ async function getOAuth2AccessToken (code, provider, codeVerifier) {
*
* 18/08/2020 @robertcraigie added results parameter to pass data to an optional request preparer.
* e.g. see providers/bungie
* @param {import("../..").Provider} provider
* @param {string} accessToken
* @param {any} results
*/
async function getOAuth2 (provider, accessToken, results) {
let url = provider.profileUrl

View File

@@ -8,7 +8,11 @@ const PKCE_LENGTH = 64
const PKCE_CODE_CHALLENGE_METHOD = 'S256' // can be 'plain', not recommended https://tools.ietf.org/html/rfc7636#section-4.2
const PKCE_MAX_AGE = 60 * 15 // 15 minutes in seconds
/** Adds `code_verifier` to `req.options.pkce`, and removes the corresponding cookie */
/**
* Adds `code_verifier` to `req.options.pkce`, and removes the corresponding cookie
* @param {import("../..").NextAuthRequest} req
* @param {import("../..").NextAuthResponse} res
*/
export async function handleCallback (req, res) {
const { cookies, provider, baseUrl, basePath } = req.options
try {
@@ -38,7 +42,11 @@ export async function handleCallback (req, res) {
}
}
/** Adds `code_challenge` and `code_challenge_method` to `req.options.pkce`. */
/**
* Adds `code_challenge` and `code_challenge_method` to `req.options.pkce`.
* @param {import("../..").NextAuthRequest} req
* @param {import("../..").NextAuthResponse} res
*/
export async function handleSignin (req, res) {
const { cookies, provider, baseUrl, basePath } = req.options
try {

View File

@@ -6,6 +6,8 @@ import { OAuthCallbackError } from '../../../lib/errors'
* For OAuth 2.0 flows, if the provider supports state,
* check if state matches the one sent on signin
* (a hash of the NextAuth.js CSRF token).
* @param {import("../..").NextAuthRequest} req
* @param {import("../..").NextAuthResponse} res
*/
export async function handleCallback (req, res) {
const { csrfToken, provider, baseUrl, basePath } = req.options
@@ -31,7 +33,11 @@ export async function handleCallback (req, res) {
}
}
/** Adds CSRF token to the authorizationParams. */
/**
* Adds CSRF token to the authorizationParams.
* @param {import("../..").NextAuthRequest} req
* @param {import("../..").NextAuthResponse} res
*/
export async function handleSignin (req, res) {
const { provider, baseUrl, basePath, csrfToken } = req.options
try {

View File

@@ -1,6 +1,7 @@
import oAuthClient from '../oauth/client'
import logger from '../../../lib/logger'
/** @param {import("../..").NextAuthRequest} req */
export default async function getAuthorizationUrl (req) {
const { provider } = req.options

View File

@@ -1,8 +1,17 @@
// @ts-check
import { h } from 'preact' // eslint-disable-line no-unused-vars
import render from 'preact-render-to-string'
/** Renders an error page. */
export default function error ({ baseUrl, basePath, error, res }) {
/**
* Renders an error page.
* @param {{
* baseUrl: string
* basePath: string
* error?: string
* res: import("..").NextAuthResponse
* }} params
*/
export default function error ({ baseUrl, basePath, error = 'default', res }) {
const signinPageUrl = `${baseUrl}${basePath}/signin`
const errors = {
@@ -37,14 +46,14 @@ export default function error ({ baseUrl, basePath, error, res }) {
message: (
<div>
<p>The sign in link is no longer valid.</p>
<p>It may have be used already or it may have expired.</p>
<p>It may have been used already or it may have expired.</p>
</div>
),
signin: <p><a className='button' href={signinPageUrl}>Sign in</a></p>
}
}
const { statusCode, heading, message, signin } = errors[error.toLowerCase()] || errors.default
const { statusCode, heading, message, signin } = errors[error.toLowerCase()]
res.status(statusCode)

View File

@@ -4,7 +4,11 @@ import * as cookie from '../lib/cookie'
import logger from '../../lib/logger'
import dispatchEvent from '../lib/dispatch-event'
/** Handle callbacks from login services */
/**
* Handle callbacks from login services
* @param {import("..").NextAuthRequest} req
* @param {import("..").NextAuthResponse} res
*/
export default async function callback (req, res) {
const {
provider,
@@ -217,12 +221,12 @@ export default async function callback (req, res) {
} else if (provider.type === 'credentials' && req.method === 'POST') {
if (!useJwtSession) {
logger.error('CALLBACK_CREDENTIALS_JWT_ERROR', 'Signin in with credentials is only supported if JSON Web Tokens are enabled')
return res.redirect(`${baseUrl}${basePath}/error?error=Configuration`)
return res.status(500).redirect(`${baseUrl}${basePath}/error?error=Configuration`)
}
if (!provider.authorize) {
logger.error('CALLBACK_CREDENTIALS_HANDLER_ERROR', 'Must define an authorize() handler to use credentials authentication provider')
return res.redirect(`${baseUrl}${basePath}/error?error=Configuration`)
return res.status(500).redirect(`${baseUrl}${basePath}/error?error=Configuration`)
}
const credentials = req.body
@@ -231,7 +235,7 @@ export default async function callback (req, res) {
try {
userObjectReturnedFromAuthorizeHandler = await provider.authorize(credentials)
if (!userObjectReturnedFromAuthorizeHandler) {
return res.redirect(`${baseUrl}${basePath}/error?error=CredentialsSignin&provider=${encodeURIComponent(provider.id)}`)
return res.status(401).redirect(`${baseUrl}${basePath}/error?error=CredentialsSignin&provider=${encodeURIComponent(provider.id)}`)
}
} catch (error) {
if (error instanceof Error) {
@@ -246,7 +250,7 @@ export default async function callback (req, res) {
try {
const signInCallbackResponse = await callbacks.signIn(user, account, credentials)
if (signInCallbackResponse === false) {
return res.redirect(`${baseUrl}${basePath}/error?error=AccessDenied`)
return res.status(403).redirect(`${baseUrl}${basePath}/error?error=AccessDenied`)
}
} catch (error) {
if (error instanceof Error) {

View File

@@ -2,6 +2,8 @@
* Return a JSON object with a list of all OAuth providers currently configured
* and their signin and callback URLs. This makes it possible to automatically
* generate buttons for all providers when rendering client side.
* @param {import("..").NextAuthRequest} req
* @param {import("..").NextAuthResponse} res
*/
export default function providers (req, res) {
const { providers } = req.options

View File

@@ -44,7 +44,7 @@ export default async function signin (req, res) {
// Check if user is allowed to sign in
try {
const signInCallbackResponse = await callbacks.signIn(profile, account, { email })
const signInCallbackResponse = await callbacks.signIn(profile, account, { email, verificationRequest: true })
if (signInCallbackResponse === false) {
return res.redirect(`${baseUrl}${basePath}/error?error=AccessDenied`)
} else if (typeof signInCallbackResponse === 'string') {

File diff suppressed because it is too large Load Diff

View File

@@ -11,8 +11,8 @@
"author": "Iain Collins <me@iaincollins.com>",
"license": "ISC",
"dependencies": {
"next": "^9.5.4",
"react": "^16.13.1",
"react-dom": "^16.13.1"
"next": "^10.0.6",
"react": "^17.0.1",
"react-dom": "^17.0.1"
}
}

48
tsconfig.json Normal file
View File

@@ -0,0 +1,48 @@
{
"compilerOptions": {
"strictNullChecks": true,
"baseUrl": ".",
"paths": {
"next-auth": [
"./src/server"
],
"next-auth/adapters": [
"./src/adapters"
],
"next-auth/client": [
"./src/client"
],
"next-auth/jwt": [
"./src/lib/jwt"
],
"next-auth/providers": [
"./src/providers"
]
},
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve"
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
]
}

View File

@@ -307,6 +307,42 @@ Set debug to `true` to enable debug messages for authentication and database ope
---
### logger
* **Default value**: `console`
* **Required**: *No*
#### Description
Override any of the logger levels (`undefined` levels will use the built-in logger), and intercept logs in NextAuth. You can use this to send NextAuth logs to a third-party logging service.
Example:
```js title="/pages/api/auth/[...nextauth].js"
import log from "logging-service"
export default NextAuth({
...
logger: {
error(code, ...message) {
log.error(code, message)
},
warn(code, ...message) {
log.warn(code, message)
}
debug(code, ...message) {
log.debug(code, message)
}
}
...
})
```
:::note
If the `debug` level is defined by the user, it will be called regardless of the `debug: false` [option](#debug).
:::
---
### theme
* **Default value**: `"auto"`

View File

@@ -118,3 +118,7 @@ You can also use the `signIn()` function which will handle obtaining the CSRF to
```js
signIn('credentials', { username: 'jsmith', password: '1234' })
```
:::tip
Remember to put any custom pages in a folder outside **/pages/api** which is reserved for API code. As per the examples above, a location convention suggestion is `pages/auth/...`.
:::

View File

@@ -112,6 +112,16 @@ providers: [
...
```
:::tip
If you think your custom provider might be useful to others, we encourage you to open a PR and add it to the built-in list so others can discover it much more easily! You only need to add three changes:
1. Add your config: [`src/providers/{provider}.js`](https://github.com/nextauthjs/next-auth/tree/main/src/providers)
2. Re-export your config: at [`src/providers/index.js`](https://github.com/nextauthjs/next-auth/blob/main/src/providers/index.js)
3. Add provider documentation: [`www/docs/providers/{provider}.md`](https://github.com/nextauthjs/next-auth/tree/main/www/docs/providers)
You can look at the existing built-in providers for inspiration.
:::
### OAuth provider options
| Name | Description | Type | Required |

View File

@@ -5,14 +5,14 @@ title: Contributors
## Core Team
* <a href="https://github.com/iaincollins">Iain Collins</a>
* <a href="https://github.com/LoriKarikari">Lori Karikari</a>
* <a href="https://github.com/ndom91">Nico Domino</a>
* <a href="https://github.com/Fumler">Fredrik Pettersen</a>
* <a href="https://github.com/geraldnolan">Gerald Nolan</a>
* <a href="https://github.com/lluia">Lluis Agusti</a>
* <a href="https://github.com/JeffersonBledsoe">Jefferson Bledsoe</a>
* <a href="https://github.com/balazsorban44">Balázs Orbán</a>
* [Iain Collins](https://github.com/iaincollins)
* [Lori Karikari](https://github.com/LoriKarikari)
* [Nico Domino](https://github.com/ndom91)
* [Fredrik Pettersen](https://github.com/Fumler)
* [Gerald Nolan](https://github.com/geraldnolan)
* [Lluis Agusti](https://github.com/lluia)
* [Jefferson Bledsoe](https://github.com/JeffersonBledsoe)
* [Balázs Orbán](https://github.com/sponsors/balazsorban44)
_Special thanks to Lori Karikari for creating most of the providers, to Nico Domino for creating this site, to Fredrik Pettersen for creating the Prisma adapter, to Gerald Nolan for adding support for Sign in with Apple, to Lluis Agusti for work to add TypeScript definitions and to Jefferson Bledsoe for working on automating testing._

View File

@@ -133,7 +133,7 @@ The `getProviders()` method returns the list of providers currently configured f
It calls `/api/auth/providers` and returns a list of the currently configured authentication providers.
It can be use useful if you are creating a dynamic custom sign in page.
It can be useful if you are creating a dynamic custom sign in page.
---
@@ -150,7 +150,7 @@ export default async (req, res) => {
```
:::note
Unlike `getSession()` and `getCsrfToken()`, when calling `getSession()` server side, you don't need to pass anything, just as calling it client side.
Unlike `getSession()` and `getCsrfToken()`, when calling `getProviders()` server side, you don't need to pass anything, just as calling it client side.
:::
---
@@ -210,6 +210,35 @@ e.g.
The URL must be considered valid by the [redirect callback handler](/configuration/callbacks#redirect). By default it requires the URL to be an absolute URL at the same hostname, or else it will redirect to the homepage. You can define your own redirect callback to allow other URLs, including supporting relative URLs.
#### Using the redirect: false option
When you use the `credentials` provider, you might not want the user to redirect to an error page if an error occurs, so you can handle any errors (like wrong credentials given by the user) on the same page. For that, you can pass `redirect: false` in the second parameter object. `signIn` then will return a Promise, that resolves to the following:
```ts
{
/**
* Will be different error codes,
* depending on the type of error.
*/
error: string | undefined
/**
* HTTP status code,
* hints the kind of error that happened.
*/
status: number
/**
* `true` if the signin was successful
*/
ok: boolean
/**
* `null` if there was an error,
* otherwise the url the user
* should have been redirected to.
*/
url: string | null
}
```
#### Additional params
It is also possible to pass additional parameters to the `/authorize` endpoint through the third argument of `signIn()`.
@@ -256,6 +285,16 @@ e.g. `signOut({ callbackUrl: 'http://localhost:3000/foo' })`
The URL must be considered valid by the [redirect callback handler](/configuration/callbacks#redirect). By default this means it must be an absolute URL at the same hostname (or else it will default to the homepage); you can define your own custom redirect callback to allow other URLs, including supporting relative URLs.
#### Using the redirect: false option
If you pass `redirect: false` to `signOut`, the page will not reload. The session will be deleted, and the `useSession` hook is notified, so any indication about the user will be shown as logged out automatically. It can give a very nice experience for the user.
:::tip
If you need to redirect to another page but you want to avoid a page reload, you can try:
`const data = await signOut({redirect: false, callbackUrl: "/foo"})`
where `data.url` is the validated url you can redirect the user to without any flicker by using Next.js's `useRouter().push(data.url)`
:::
---
## Provider

View File

@@ -9,8 +9,6 @@ https://developer.atlassian.com/cloud/jira/platform/oauth-2-authorization-code-g
## Example
For Jira Platform API access:
```js
import Providers from `next-auth/providers`
...
@@ -18,8 +16,7 @@ providers: [
Providers.Atlassian({
clientId: process.env.ATLASSIAN_CLIENT_ID,
clientSecret: process.env.ATLASSIAN_CLIENT_SECRET,
scope:
'write:jira-work read:jira-work read:jira-user offline_access read:me',
scope: 'write:jira-work read:jira-work read:jira-user offline_access read:me'
})
]
...
@@ -33,7 +30,7 @@ providers: [
An app can be created at https://developer.atlassian.com/apps/
:::
Under "Apis and features" side menu, configure the following for the "OAuth 2.0 (3LO)"
Under "Apis and features" in the side menu, configure the following for "OAuth 2.0 (3LO)":
- Redirect URL
- http://localhost:3000/api/auth/callback/atlassian

View File

@@ -12,7 +12,23 @@ https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-c
https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-tenant
## Example
- In https://portal.azure.com/ -> Azure Active Directory create a new App Registration.
- Make sure to remember / copy
- Application (client) ID
- Directory (tenant) ID
- When asked for a redirection URL, use http://localhost:3000/api/auth/callback/azure-ad-b2c
- Create a new secret and remember / copy its value immediately, it will disappear.
In `.env.local` create the follwing entries:
```
AZURE_CLIENT_ID=<copy Application (client) ID here>
AZURE_CLIENT_SECRET=<copy generated secret value here>
AZURE_TENANT_ID=<copy the tenant id here>
```
In `pages/api/auth/[...nextauth].js` find or add the AZURE entries:
```js
import Providers from 'next-auth/providers';
...
@@ -25,4 +41,5 @@ providers: [
}),
]
...
```

View File

@@ -0,0 +1,57 @@
---
id: eveonline
title: EVE Online
---
## Documentation
https://developers.eveonline.com/blog/article/sso-to-authenticated-calls
## Configuration
https://developers.eveonline.com/
## Example
```js
import Providers from `next-auth/providers`
...
providers: [
Providers.EVEOnline({
clientId: process.env.EVE_CLIENT_ID,
clientSecret: process.env.EVE_CLIENT_SECRET
})
]
...
```
:::tip When creating your application, make sure to select `Authentication Only` as the connection type.
:::tip If using JWT for the session, you can add the `CharacterID` to the JWT token and session. Example:
```js
...
options: {
jwt: {
secret: process.env.JWT_SECRET,
},
callbacks: {
jwt: async (token, user, account, profile, isNewUser) => {
if (profile) {
token = {
...token,
id: profile.CharacterID,
}
}
return token;
},
session: async (session, token) => {
if (token) {
session.user.id = token.id;
}
return session;
}
}
}
...
```

View File

@@ -1,6 +1,6 @@
---
id: vk
title: vk.com
title: VK
---
## Documentation

View File

@@ -55,13 +55,13 @@ However, it should not be enabled against production databases as it may cause d
## Prisma Adapter
You can also use NextAuth.js with [Prisma](https://www.prisma.io/docs/).
You can also use NextAuth.js with the experimental adapter for [Prisma 2](https://www.prisma.io/docs/).
To use this adapter, you need to install Prisma Client and Prisma CLI:
```
npm i @prisma/client
npm add -D @prisma/cli
npm install @prisma/client
npm install prisma --save-dev
```
Configure your NextAuth.js to use the Prisma adapter:
@@ -91,7 +91,7 @@ While Prisma includes an experimental feature in the migration command that is a
### Prisma Schema
Create a `schema.prisma` file similar to this one:
Create a schema file in `prisma/schema.prisma` similar to this one:
```json title="schema.prisma"
generator client {
@@ -179,12 +179,22 @@ datasource db {
### Generate Client
Once you have saved your schema, you can run the Prisma CLI to generate the Prisma Client:
Once you have saved your schema, use the Prisma CLI to generate the Prisma Client:
```
npx @prisma/cli generate
npx prisma generate
```
To configure you database to use the new schema (i.e. create tables and columns) use the `primsa migrate` command:
```
npx prisma migrate dev --preview-feature
```
To generate a schema in this way with the above example code, you will need to specify your datbase connection string in the environment variable `DATABASE_URL`. You can do this by setting it in a `.env` file at the root of your project.
As this feature is experimental in Prisma, it is behind a feature flag. You should check your database schema manually after using this option. See the [Prisma documentation](https://www.prisma.io/docs/) for information on how to use `prisma migrate`.
### Custom Models
You can add properties to the schema and map them to any database column names you wish, but you should not change the base properties or types defined in the example schema.

View File

@@ -68,7 +68,7 @@ module.exports = {
to: '/contributors'
},
{
label: 'Canary docs',
label: 'Canary documentation',
to: 'https://next-auth-git-canary.nextauthjs.vercel.app/'
}
]

View File

@@ -2,12 +2,13 @@
"name": "next-auth-docs",
"version": "0.1.1",
"scripts": {
"start": "docusaurus start",
"build": "docusaurus build",
"start": "npm run generate-providers && docusaurus start",
"build": "npm run generate-providers && docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
"lint": "standard",
"lint:fix": "standard --fix"
"lint:fix": "standard --fix",
"generate-providers": "node ./scripts/generate-providers.js"
},
"dependencies": {
"@docusaurus/core": "^2.0.0-alpha.66",

View File

@@ -1,36 +0,0 @@
{
"apple": "Apple",
"atlassian": "Atlassian",
"auth0": "Auth0",
"azure-ad-b2c": "Azure Active Directory B2C",
"basecamp": "Basecamp",
"battle.net": "Battle.net",
"box": "Box",
"bungie": "Bungie",
"cognito": "Amazon Cognito",
"credentials": "Credentials",
"discord": "Discord",
"email": "Email",
"facebook": "Facebook",
"foursquare": "Foursquare",
"fusionauth": "FusionAuth",
"github": "GitHub",
"gitlab": "GitLab",
"google": "Google",
"identity-server4": "IdentityServer4",
"line": "LINE",
"linkedin": "LinkedIn",
"mailru": "Mail.ru",
"medium": "Medium",
"netlify": "Netlify",
"okta": "Okta",
"reddit": "Reddit",
"salesforce": "Salesforce",
"slack": "Slack",
"spotify": "Spotify",
"strava": "Strava",
"twitch": "Twitch",
"twitter": "Twitter",
"vk": "VK",
"yandex": "Yandex"
}

View File

@@ -0,0 +1,15 @@
const path = require('path')
const fs = require('fs')
const providersPath = path.join(process.cwd(), '/docs/providers')
const files = fs.readdirSync(providersPath, 'utf8')
const result = files.reduce((acc, file) => {
const provider = fs.readFileSync(path.join(providersPath, file), 'utf8')
const { id, title } = provider.match(/id: (?<id>.+)\ntitle: (?<title>.+)\n/).groups
acc[id] = title
return acc
}, {})
fs.writeFileSync(path.join(process.cwd(), 'providers.json'), JSON.stringify(result, null, 2))