diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 32343497..00000000 --- a/.eslintignore +++ /dev/null @@ -1,70 +0,0 @@ -.eslintrc.js -.cache-loader -.DS_Store -.pnpm-debug.log -.turbo -.vscode/generated* -/_work -/actions-runner -node_modules -patches -pnpm-lock.yaml -.github/actions/issue-validator/index.mjs -*.cjs -*.js -*.d.ts -*.d.ts.map - -.svelte-kit -.next -.nuxt - -# --------------- Docs --------------- - -.docusaurus -build -docs/docs/reference/core -docs/docs/reference/sveltekit -static - -# --------------- Packages --------------- - -coverage -dist - -# @auth/core -packages/core/src/providers/oauth-types.ts -packages/core/src/lib/pages/styles.ts - -# @auth/sveltekit -packages/frameworks-sveltekit/package -packages/frameworks-sveltekit/vite.config.{js,ts}.timestamp-* - -# next-auth -packages/next-auth/src/providers/oauth-types.ts -packages/next-auth/css/index.css - - -# Adapters -.branches -db.sqlite -dev.db -dynamodblocal-bin -firebase-debug.log -firestore-debug.log -migrations -test.schema.gql - -# --------------- Apps --------------- - - -# Examples should have their own Prettier config since they are templates too -apps/example-sveltekit - -# Development app -apps - - -# --------------- Tests --------------- -# TODO: these should be linted -packages/**/*test* \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 802d0ab7..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,75 +0,0 @@ -// @ts-check - -/** @type {import("eslint").ESLint.ConfigData} */ -module.exports = { - env: { browser: true, es2022: true, node: true }, - extends: ["eslint:recommended", "prettier"], - overrides: [ - { - files: ["*.ts", "*.tsx"], - parser: "@typescript-eslint/parser", - parserOptions: { - project: ["./packages/**/tsconfig.json", "./apps/**/tsconfig.json"], - }, - settings: { react: { version: "18" } }, - extends: [ - "plugin:react/recommended", - "plugin:react/jsx-runtime", - "standard-with-typescript", - "prettier", - ], - rules: { - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/method-signature-style": "off", - "@typescript-eslint/naming-convention": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/restrict-template-expressions": "off", - "@typescript-eslint/strict-boolean-expressions": "off", - "react/prop-types": "off", - "react/no-unescaped-entities": "off", - }, - }, - { - files: ["*.test.ts", "*.test.js"], - extends: ["plugin:jest/recommended"], - env: { jest: true }, - }, - { - files: ["docs/**"], - plugins: ["@docusaurus"], - extends: ["plugin:@docusaurus/recommended"], - }, - { - // TODO: Expand to all packages - files: ["packages/{core,sveltekit}/*.ts"], - plugins: ["jsdoc"], - extends: ["plugin:jsdoc/recommended"], - rules: { - "jsdoc/require-param": "off", - "jsdoc/require-returns": "off", - "jsdoc/require-jsdoc": [ - "warn", - { publicOnly: true, enableFixer: false }, - ], - "jsdoc/no-multi-asterisks": ["warn", { allowWhitespace: true }], - "jsdoc/tag-lines": "off", - }, - }, - { - files: ["packages/frameworks-sveltekit"], - plugins: ["svelte3"], - overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }], - settings: { - "svelte3/typescript": () => require("typescript"), - }, - parserOptions: { sourceType: "module", ecmaVersion: 2020 }, - env: { browser: true, es2017: true, node: true }, - }, - ], - parserOptions: { - sourceType: "module", - ecmaVersion: "latest", - ecmaFeatures: { jsx: true }, - }, - root: true, -} diff --git a/.github/ISSUE_TEMPLATE/2_bug_provider.yml b/.github/ISSUE_TEMPLATE/2_bug_provider.yml index e5d343b0..ebacb231 100644 --- a/.github/ISSUE_TEMPLATE/2_bug_provider.yml +++ b/.github/ISSUE_TEMPLATE/2_bug_provider.yml @@ -32,6 +32,7 @@ body: - "Azure Active Directory" - "Azure Active Directory B2C" - "Battlenet" + - "Beyond Identity" - "Box" - "Bungie" - "Cognito" diff --git a/.github/actions/issue-validator/repro.md b/.github/actions/issue-validator/repro.md index 9fda1cad..96e78050 100644 --- a/.github/actions/issue-validator/repro.md +++ b/.github/actions/issue-validator/repro.md @@ -14,9 +14,9 @@ Ensure the link is pointing to a codebase that is accessible (e.g. not a private ### **What happens if I don't provide a sufficient minimal reproduction?** -Issues with the `incomplete` label that receives no meaningful activity (e.g. new comments with a reproduction link) are automatically closed and locked after 30 days. +Issues with the `incomplete` label that receives no meaningful activity (e.g. new comments with a reproduction link) are closed after 7 days. -If your issue has _not_ been resolved in that time and it has been closed/locked, please open a new issue with the required reproduction. +If your issue has _not_ been resolved in that time and it has been closed/locked, please open a new issue with the required reproduction. (It's less likely that we check back on already closed issues.) ### **I did not open this issue, but it is relevant to me, what can I do to help?** diff --git a/.github/sync.yml b/.github/sync.yml index f26108e5..cb94a7fc 100644 --- a/.github/sync.yml +++ b/.github/sync.yml @@ -1,5 +1,3 @@ -# Note that nextauthjs/next-auth-example syncs from the v4 branch - nextauthjs/sveltekit-auth-example: - source: apps/examples/sveltekit dest: . @@ -20,3 +18,10 @@ nextauthjs/next-auth-gatsby-example: deleteOrphaned: true - .github/FUNDING.yml - LICENSE + +nextauthjs/next-auth-example: + - source: apps/examples/nextjs + dest: . + deleteOrphaned: true + - .github/FUNDING.yml + - LICENSE diff --git a/.github/version-pr/index.js b/.github/version-pr/index.js index 4ce04da1..7936f651 100644 --- a/.github/version-pr/index.js +++ b/.github/version-pr/index.js @@ -5,14 +5,15 @@ const core = require("@actions/core") try { const packageJSONPath = path.join( process.cwd(), - "packages/next-auth/package.json" + `packages/${process.env.PACKAGE_PATH || "next-auth"}/package.json` ) const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, "utf8")) const sha8 = process.env.GITHUB_SHA.substring(0, 8) - const prNumber = process.env.PR_NUMBER - - const packageVersion = `0.0.0-pr.${prNumber}.${sha8}` + const prefix = "0.0.0-" + const pr = process.env.PR_NUMBER + const source = pr ? `pr.${pr}` : "manual" + const packageVersion = `${prefix}${source}.${sha8}` packageJSON.version = packageVersion core.setOutput("version", packageVersion) fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON)) diff --git a/.github/workflows/issue-validator.yml b/.github/workflows/issue-validator.yml index d6d05c75..25272a35 100644 --- a/.github/workflows/issue-validator.yml +++ b/.github/workflows/issue-validator.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/setup-node@v3 with: node-version: 18 - - name: "Run issue validator" + - name: Run issue validator run: node /home/runner/work/next-auth/next-auth/.github/actions/issue-validator/index.mjs env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 919e9390..6a55a2f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,11 +3,29 @@ name: Release on: push: branches: - - "main" - - "beta" - - "next" - - "3.x" + - main + - beta + - next + - 3.x pull_request: + # TODO: Support latest releases + workflow_dispatch: + inputs: + name: + type: choice + description: Package name (npm) + options: + - "@auth/nextjs" + - "@auth/core" + - "next-auth" + # TODO: Infer from package name + path: + type: choice + description: Directory name (packages/*) + options: + - "frameworks-nextjs" + - "core" + - "next-auth" jobs: test: @@ -24,7 +42,6 @@ jobs: uses: actions/setup-node@v3 with: node-version: 18 - cache: "pnpm" - name: Install dependencies run: pnpm install - name: Run tests @@ -74,7 +91,6 @@ jobs: uses: actions/setup-node@v3 with: node-version: 18 - cache: "pnpm" - name: Install dependencies run: pnpm install - name: Publish to npm and GitHub @@ -99,7 +115,6 @@ jobs: uses: actions/setup-node@v3 with: node-version: 18 - cache: "pnpm" - name: Install dependencies run: pnpm install - name: Determine version @@ -125,3 +140,34 @@ jobs: env: VERSION: ${{ steps.determine-version.outputs.version }} GITHUB_TOKEN: ${{ secrets.GH_PAT }} + release-manual: + name: Publish manually + runs-on: ubuntu-latest + if: ${{ github.event_name == 'workflow_dispatch' }} + steps: + - name: Init + uses: actions/checkout@v3 + - name: Install pnpm + uses: pnpm/action-setup@v2.2.4 + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Install dependencies + run: pnpm install + - name: Determine version + uses: ./.github/version-pr + id: determine-version + env: + PACKAGE_PATH: ${{ github.event.inputs.path }} + - name: Publish to npm + run: | + cd packages/$PACKAGE_PATH + echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> .npmrc + pnpm publish --no-git-checks --access public --tag experimental + echo "🎉 Experimental release published 📦️ on npm: https://npmjs.com/package/${{ github.event.inputs.name }}/v/${{ env.VERSION }}" + echo "Install via: pnpm add ${{ github.event.inputs.name }}@${{ env.VERSION }}" + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + PACKAGE_PATH: ${{ github.event.inputs.path }} + VERSION: ${{ steps.determine-version.outputs.version }} diff --git a/.gitignore b/.gitignore index 1f4e2442..77b19873 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ # Misc .DS_Store -.npmrc .eslintcache .env .env.local @@ -14,7 +13,7 @@ yarn-error.log* firebase-debug.log ui-debug.log .pnpm-debug.log - +.husky # Dependencies node_modules @@ -44,6 +43,7 @@ packages/*/*.d.ts.map apps/dev/src/css apps/dev/prisma/migrations apps/dev/typeorm +apps/dev/nextjs-2 # VS /.vs/slnx.sqlite-journal diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..f0c0c3df --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +public-hoist-pattern[]=*prisma* diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index fc17898f..00000000 --- a/.prettierrc.js +++ /dev/null @@ -1,22 +0,0 @@ -// @ts-check - -/** @type {import("prettier").Config} */ -module.exports = { - semi: false, - singleQuote: false, - overrides: [ - { - files: [ - "apps/dev/nextjs/pages/api/auth/[...nextauth].ts", - "docs/{sidebars,docusaurus.config}.js", - ], - options: { printWidth: 150 }, - }, - { - files: ["**/*package.json"], - options: { - trailingComma: "none", - }, - }, - ], -} diff --git a/apps/dev/nextjs-v4/.env.local.example b/apps/dev/nextjs-v4/.env.local.example new file mode 100644 index 00000000..fa6a263d --- /dev/null +++ b/apps/dev/nextjs-v4/.env.local.example @@ -0,0 +1,58 @@ +# Rename file to .env.local (or .env) and populate values +# to be able to run the dev app + +NEXTAUTH_URL=http://localhost:3000 + +# You can use `openssl rand -hex 32` or +# https://generate-secret.vercel.app/32 to generate a secret. +# Note: Changing a secret may invalidate existing sessions +# and/or verification tokens. +NEXTAUTH_SECRET=secret + +AUTH0_ID= +AUTH0_SECRET= +AUTH0_ISSUER= + +KEYCLOAK_ID= +KEYCLOAK_SECRET= +KEYCLOAK_ISSUER= + +IDS4_ID= +IDS4_SECRET= +IDS4_ISSUER= + +GITHUB_ID= +GITHUB_SECRET= + +TWITCH_ID= +TWITCH_SECRET= + +TWITTER_ID= +TWITTER_SECRET= + +LINE_ID= +LINE_SECRET= + +TRAKT_ID= +TRAKT_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 + +# 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= + +WIKIMEDIA_ID= +WIKIMEDIA_SECRET= + +# Supabase Example Configuration +# Supabase Example Configuration +# NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321 +# SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSJ9.vI9obAHOGyVVKa3pD--kJlyxp-Z2zV9UUMAhKpNLAcU +# SUPABASE_JWT_SECRET=super-secret-jwt-token-with-at-least-32-characters-long +# NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs \ No newline at end of file diff --git a/apps/dev/nextjs-v4/.vscode/settings.json b/apps/dev/nextjs-v4/.vscode/settings.json new file mode 100644 index 00000000..d73b11f1 --- /dev/null +++ b/apps/dev/nextjs-v4/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "typescript.tsdk": "../../node_modules/.pnpm/typescript@4.8.4/node_modules/typescript/lib", + "typescript.enablePromptUseWorkspaceTsdk": true +} \ No newline at end of file diff --git a/apps/dev/nextjs-v4/README.md b/apps/dev/nextjs-v4/README.md new file mode 100644 index 00000000..81886214 --- /dev/null +++ b/apps/dev/nextjs-v4/README.md @@ -0,0 +1,6 @@ +# NextAuth.js Development App + +This folder contains a Next.js app using NextAuth.js for local development. See the following section on how to start: + +[Setting up local environment +](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md#setting-up-local-environment) \ No newline at end of file diff --git a/apps/dev/nextjs-v4/app/api/auth/[...nextauth]/route.ts b/apps/dev/nextjs-v4/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 00000000..faa13c60 --- /dev/null +++ b/apps/dev/nextjs-v4/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,14 @@ +import NextAuth, { type NextAuthOptions } from "next-auth" +import GitHub from "next-auth/providers/github" + +export const authOptions: NextAuthOptions = { + providers: [ + GitHub({ + clientId: process.env.GITHUB_ID, + clientSecret: process.env.GITHUB_SECRET, + }), + ], +} + +const handler = NextAuth(authOptions) +export { handler as GET, handler as POST } diff --git a/apps/dev/nextjs-v4/app/layout.tsx b/apps/dev/nextjs-v4/app/layout.tsx new file mode 100644 index 00000000..7f2b6717 --- /dev/null +++ b/apps/dev/nextjs-v4/app/layout.tsx @@ -0,0 +1,12 @@ +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + + {children} + + ) +} diff --git a/apps/dev/nextjs-v4/app/server-component/page.tsx b/apps/dev/nextjs-v4/app/server-component/page.tsx new file mode 100644 index 00000000..a5bd9003 --- /dev/null +++ b/apps/dev/nextjs-v4/app/server-component/page.tsx @@ -0,0 +1,6 @@ +import { getServerSession } from "next-auth/next" + +export default async function Page() { + const session = await getServerSession() + return
{JSON.stringify(session, null, 2)}
+} diff --git a/apps/dev/nextjs-v4/components/access-denied.js b/apps/dev/nextjs-v4/components/access-denied.js new file mode 100644 index 00000000..4c9c0d79 --- /dev/null +++ b/apps/dev/nextjs-v4/components/access-denied.js @@ -0,0 +1,20 @@ +import { signIn } from "next-auth/react" + +export default function AccessDenied() { + return ( + <> +

Access Denied

+

+ { + e.preventDefault() + signIn() + }} + > + You must be signed in to view this page + +

+ + ) +} diff --git a/apps/dev/nextjs-v4/components/footer.js b/apps/dev/nextjs-v4/components/footer.js new file mode 100644 index 00000000..92b5df9b --- /dev/null +++ b/apps/dev/nextjs-v4/components/footer.js @@ -0,0 +1,28 @@ +import Link from "next/link" +import styles from "./footer.module.css" +import packageJSON from "package.json" + +export default function Footer() { + return ( + + ) +} diff --git a/apps/dev/nextjs-v4/components/footer.module.css b/apps/dev/nextjs-v4/components/footer.module.css new file mode 100644 index 00000000..bf8bfb82 --- /dev/null +++ b/apps/dev/nextjs-v4/components/footer.module.css @@ -0,0 +1,14 @@ +.footer { + margin-top: 2rem; +} + +.navItems { + margin-bottom: 1rem; + padding: 0; + list-style: none; +} + +.navItem { + display: inline-block; + margin-right: 1rem; +} \ No newline at end of file diff --git a/apps/dev/nextjs-v4/components/header.js b/apps/dev/nextjs-v4/components/header.js new file mode 100644 index 00000000..ae06058a --- /dev/null +++ b/apps/dev/nextjs-v4/components/header.js @@ -0,0 +1,103 @@ +import Link from "next/link" +import { signIn, signOut, useSession } from "next-auth/react" +import styles from "./header.module.css" + +// The approach used in this component shows how to built a sign in and sign out +// component that works on pages which support both client and server side +// rendering, and avoids any flash incorrect content on initial page load. +export default function Header() { + const { data: session, status } = useSession() + + return ( +
+ +
+

+ {!session && ( + <> + + You are not signed in + + { + e.preventDefault() + signIn() + }} + > + Sign in + + + )} + {session && ( + <> + {session.user.image && ( + + )} + + Signed in as +
+ {session.user.email} + {session.user.name ? `(${session.user.name})` : null} +
+ { + e.preventDefault() + signOut() + }} + > + Sign out + + + )} +

+
+ +
+ ) +} diff --git a/apps/dev/nextjs-v4/components/header.module.css b/apps/dev/nextjs-v4/components/header.module.css new file mode 100644 index 00000000..18ec82f0 --- /dev/null +++ b/apps/dev/nextjs-v4/components/header.module.css @@ -0,0 +1,92 @@ +/* Set min-height to avoid page reflow while session loading */ +.signedInStatus { + display: block; + min-height: 4rem; + width: 100%; +} + +.loading, +.loaded { + position: relative; + top: 0; + opacity: 1; + overflow: hidden; + border-radius: 0 0 .6rem .6rem; + padding: .6rem 1rem; + margin: 0; + background-color: rgba(0,0,0,.05); + transition: all 0.2s ease-in; +} + +.loading { + top: -2rem; + opacity: 0; +} + +.signedInText, +.notSignedInText { + position: absolute; + padding-top: .8rem; + left: 1rem; + right: 6.5rem; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + display: inherit; + z-index: 1; + line-height: 1.3rem; +} + +.signedInText { + padding-top: 0rem; + left: 4.6rem; +} + +.avatar { + border-radius: 2rem; + float: left; + height: 2.8rem; + width: 2.8rem; + background-color: white; + background-size: cover; + background-repeat: no-repeat; +} + +.button, +.buttonPrimary { + float: right; + margin-right: -.4rem; + font-weight: 500; + border-radius: .3rem; + cursor: pointer; + font-size: 1rem; + line-height: 1.4rem; + padding: .7rem .8rem; + position: relative; + z-index: 10; + background-color: transparent; + color: #555; +} + +.buttonPrimary { + background-color: #346df1; + border-color: #346df1; + color: #fff; + text-decoration: none; + padding: .7rem 1.4rem; +} + +.buttonPrimary:hover { + box-shadow: inset 0 0 5rem rgba(0,0,0,0.2) +} + +.navItems { + margin-bottom: 2rem; + padding: 0; + list-style: none; +} + +.navItem { + display: inline-block; + margin-right: 1rem; +} \ No newline at end of file diff --git a/apps/dev/nextjs-v4/components/layout.js b/apps/dev/nextjs-v4/components/layout.js new file mode 100644 index 00000000..6c4fcc7d --- /dev/null +++ b/apps/dev/nextjs-v4/components/layout.js @@ -0,0 +1,14 @@ +import Header from 'components/header' +import Footer from 'components/footer' + +export default function Layout ({ children }) { + return ( + <> +
+
+ {children} +
+