diff --git a/.github/ISSUE_TEMPLATE/2_bug_provider.yml b/.github/ISSUE_TEMPLATE/2_bug_provider.yml index 630d8af92c..406084ea8d 100644 --- a/.github/ISSUE_TEMPLATE/2_bug_provider.yml +++ b/.github/ISSUE_TEMPLATE/2_bug_provider.yml @@ -57,10 +57,12 @@ body: - "Identity Server 4" - "Instagram" - "Kakao" + - "Frontegg" - "Keycloak" - "Kinde" - "Line" - "LinkedIn" + - "Loops" - "Mailchimp" - "Mail.ru" - "Mastodon" diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..ea6feea960 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "npm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + versioning-strategy: "increase" + allow: + - dependency-name: "oauth4webapi" + - dependency-name: "jose" diff --git a/.github/pr-labeler.yml b/.github/pr-labeler.yml index 9e44ccb35f..0886682be2 100644 --- a/.github/pr-labeler.yml +++ b/.github/pr-labeler.yml @@ -9,6 +9,7 @@ drizzle: ["packages/adapter-drizzle/**/*"] documentation: ["packages/docs/docs/**/*"] dynamodb: ["packages/adapter-dynamodb/**/*"] examples: ["apps/examples/**/*"] +express: ["packages/frameworks-express/**/*"] fauna: ["packages/adapter-fauna/**/*"] firebase: ["packages/adapter-firebase/**/*"] hasura: ["packages/adapter-hasura/**/*"] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6a106bc90d..1ee78afa19 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,7 +59,7 @@ env: jobs: test: name: Test - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Init uses: actions/checkout@v4 @@ -107,7 +107,7 @@ jobs: run: cd apps/examples/nextjs-docker && pnpm test:docker - name: Run E2E tests continue-on-error: true # TODO: Make this less flakey - if: github.repository == 'nextauthjs/next-auth' + if: ${{ env.PACKAGES_CHANGES == 'true' || github.ref == 'refs/heads/main' }} timeout-minutes: 15 env: AUTH_SECRET: ${{ secrets.AUTH_SECRET }} diff --git a/.gitignore b/.gitignore index 66ce6a85ba..2ac352effe 100644 --- a/.gitignore +++ b/.gitignore @@ -87,7 +87,7 @@ docs/.next docs/manifest.mjs # Core -packages/core/src/providers/oauth-types.ts +packages/core/src/providers/provider-types.ts packages/core/lib packages/core/providers packages/core/src/lib/pages/styles.ts diff --git a/.prettierignore b/.prettierignore index af5e116db3..5838858cf7 100644 --- a/.prettierignore +++ b/.prettierignore @@ -32,7 +32,7 @@ packages/**/*.js !packages/*/scripts/*.js # @auth/core -packages/core/src/providers/oauth-types.ts +packages/core/src/providers/provider-types.ts packages/core/src/lib/pages/styles.ts # @auth/sveltekit @@ -43,7 +43,7 @@ packages/frameworks-sveltekit/vite.config.{js,ts}.timestamp-* packages/frameworks-express/providers # next-auth -packages/next-auth/src/providers/oauth-types.ts +packages/next-auth/src/providers/provider-types.ts packages/next-auth/css/index.css # Adapters diff --git a/README.md b/README.md index c088ae7d9a..4a8005f3a1 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,15 @@ We have an [OpenCollective](https://opencollective.com/nextauth) for companies a
Or jump directly to one of the popular ones below.
-Can't find the OAuth provider you're looking for? You can always{" "} @@ -119,17 +95,11 @@ export function OAuthProviderSelect() { .
- ) : null} + )}
First you have to setup an OAuth application on the {providerName}{" "}
developers dashboard.
@@ -115,7 +115,7 @@ export function OAuthInstructions({ providerId, disabled = false }: Props) {
environment(s).
{/* Step 2 */}
-
Once registered, you should receive a{" "} {manifest.requiresIssuer.includes(providerId) ? ( @@ -132,40 +132,48 @@ export function OAuthInstructions({ providerId, disabled = false }: Props) {
-
+
+
+
+
+
-
+
+
+
+
+
-
+
+
+
+
+
-
+
+
+
+
+
Assuming{" "}
@@ -188,7 +196,7 @@ export function OAuthInstructions({ providerId, disabled = false }: Props) {
if needed, but then you’ll need to pass them to the provider manually.
{/* Step 3 */}
- Setup Provider
+ Setup Provider
Let’s enable {providerName} as a sign in option in our Auth.js
configuration. You’ll have to import the {providerName} {" "}
@@ -201,7 +209,7 @@ export function OAuthInstructions({ providerId, disabled = false }: Props) {
highlight={highlight}
/>
{/* Step 4 */}
- Add Signin Button
+ Add Signin Button
Next, we can add a signin button somewhere in your application like the
Navbar. It will trigger Auth.js sign in when clicked.
@@ -212,7 +220,7 @@ export function OAuthInstructions({ providerId, disabled = false }: Props) {
highlight={highlight}
/>
{/* Step 5 */}
- Ship it!
+ Ship it!
Click the “Sign in with {providerName}" button and if all went well, you
should be redirected to {providerName} and once authenticated,
diff --git a/docs/components/OAuthProviderInstructions/useOAuthProviderSelect.ts b/docs/components/OAuthProviderInstructions/useOAuthProviderSelect.ts
deleted file mode 100644
index 97d5072861..0000000000
--- a/docs/components/OAuthProviderInstructions/useOAuthProviderSelect.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { useState } from "react"
-import manifest from "@/data/manifest.json"
-
-const providerList = Object.entries(manifest.providersOAuth).map(
- ([id, name]) => {
- return { id, name }
- }
-)
-
-export function useOAuthProviderSelect() {
- const [term, setTerm] = useState("")
- const [selected, setSelected] = useState("")
-
- function handleSearchItem(term: string) {
- setTerm(term)
- }
-
- function handleSelectOption(item: { id: string; name: string }) {
- setTerm(item.name)
- setSelected(item.id)
- }
-
- return {
- items: providerList.filter((item) =>
- item.name.toLowerCase().includes(term?.toLowerCase())
- ),
- term,
- selected,
- handleSearchItem,
- handleSelectOption,
- }
-}
diff --git a/docs/components/SearchBarProviders/PreviewProviders.tsx b/docs/components/SearchBarProviders/PreviewProviders.tsx
new file mode 100644
index 0000000000..d1fdfdb0f2
--- /dev/null
+++ b/docs/components/SearchBarProviders/PreviewProviders.tsx
@@ -0,0 +1,35 @@
+export interface Provider {
+ id: string
+ name: string
+}
+
+export interface PreviewProvidersProps {
+ className?: string
+ providers: Provider[]
+ onSelected: (provider: Provider) => void
+}
+
+export function PreviewProviders({
+ className,
+ providers,
+ onSelected,
+}: PreviewProvidersProps) {
+ return (
+
+ {providers.map((provider) => (
+ onSelected(provider)}
+ >
+
+ {provider.name}
+
+ ))}
+
+ )
+}
diff --git a/docs/hooks/use-select-combobox.ts b/docs/hooks/use-select-combobox.ts
new file mode 100644
index 0000000000..b8ee43a0dc
--- /dev/null
+++ b/docs/hooks/use-select-combobox.ts
@@ -0,0 +1,48 @@
+import { ChangeEvent, useState } from "react"
+
+interface SelectComboboxValue {
+ id: string
+ name: string
+}
+
+interface SelectComboboxProps {
+ defaultValue?: SelectComboboxValue
+ items: SelectComboboxValue[]
+}
+
+export const useSelectCombobox = ({
+ defaultValue = { id: "", name: "" },
+ items,
+}: SelectComboboxProps) => {
+ const [selectedItem, setSelectedItem] =
+ useState(defaultValue)
+ const [filteredItems, setFilteredItems] = useState(items)
+ const [hasMatchItem, setHasMatchItem] = useState(false)
+
+ const handleSelect = (value: SelectComboboxValue) => {
+ let hasMatchItem = false
+ setFilteredItems(
+ items.filter((item) => {
+ if (item.id === value.id) {
+ hasMatchItem = true
+ }
+ return item.name.toLowerCase().includes(value.name.toLowerCase())
+ })
+ )
+ setSelectedItem(value)
+ setHasMatchItem(hasMatchItem)
+ }
+
+ const handleChange = (event: ChangeEvent) => {
+ const { value } = event.target
+ handleSelect({ id: value, name: value })
+ }
+
+ return {
+ selectedItem,
+ filteredItems,
+ handleSelect,
+ handleChange,
+ hasMatchItem,
+ }
+}
diff --git a/docs/package.json b/docs/package.json
index 3e97446a33..75b2da8a8b 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -36,8 +36,8 @@
"framer-motion": "^11.11.8",
"next": "14.2.15",
"next-sitemap": "^4.2.3",
- "nextra": "3.0.0-alpha.24",
- "nextra-theme-docs": "3.0.0-alpha.24",
+ "nextra": "3.0.15",
+ "nextra-theme-docs": "3.0.15",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-instantsearch": "^7.13.3",
diff --git a/docs/pages/data/manifest.json b/docs/pages/data/manifest.json
index bbeb72499f..b9bba6f916 100644
--- a/docs/pages/data/manifest.json
+++ b/docs/pages/data/manifest.json
@@ -62,7 +62,7 @@
"box": "Box",
"boxyhq-saml": "BoxyHQ SAML",
"bungie": "Bungie",
- "clickup": "ClickUp",
+ "click-up": "ClickUp",
"cognito": "Cognito",
"coinbase": "Coinbase",
"descope": "Descope",
diff --git a/docs/pages/getting-started/adapters/drizzle.mdx b/docs/pages/getting-started/adapters/drizzle.mdx
index 84ed30eeda..95a440a543 100644
--- a/docs/pages/getting-started/adapters/drizzle.mdx
+++ b/docs/pages/getting-started/adapters/drizzle.mdx
@@ -34,8 +34,8 @@ To use this adapter, you must have setup Drizzle ORM and Drizzle Kit in your pro
1. Create your schema file, based off of one of the ones below.
2. Install a supported database driver to your project, like `@libsql/client`, `mysql2` or `postgres`.
3. Create a `drizzle.config.ts` [file](https://orm.drizzle.team/kit-docs/conf).
-4. Generate the initial migration from your schema file with a command like, `drizzle-kit generate:pg`.
-5. Apply migrations by using `migrate()` function or push changes directly to your database with a command like, `drizzle-kit push:pg`.
+4. Generate the initial migration from your schema file with a command like, `drizzle-kit generate`.
+5. Apply migrations by using `migrate()` function or push changes directly to your database with a command like, `drizzle-kit push`.
6. If your schemas differ from the default ones, pass them as the second parameter to the adapter.
#### Schemas
@@ -89,12 +89,14 @@ export const accounts = pgTable(
id_token: text("id_token"),
session_state: text("session_state"),
},
- (account) => ({
- compoundKey: primaryKey({
- columns: [account.provider, account.providerAccountId],
- }),
- })
-)
+ (account) => [
+ {
+ compoundKey: primaryKey({
+ columns: [account.provider, account.providerAccountId],
+ }),
+ },
+ ],
+);
export const sessions = pgTable("session", {
sessionToken: text("sessionToken").primaryKey(),
@@ -111,12 +113,14 @@ export const verificationTokens = pgTable(
token: text("token").notNull(),
expires: timestamp("expires", { mode: "date" }).notNull(),
},
- (verificationToken) => ({
- compositePk: primaryKey({
- columns: [verificationToken.identifier, verificationToken.token],
- }),
- })
-)
+ (verificationToken) => [
+ {
+ compositePk: primaryKey({
+ columns: [verificationToken.identifier, verificationToken.token],
+ }),
+ },
+ ],
+);
export const authenticators = pgTable(
"authenticator",
@@ -132,12 +136,14 @@ export const authenticators = pgTable(
credentialBackedUp: boolean("credentialBackedUp").notNull(),
transports: text("transports"),
},
- (authenticator) => ({
- compositePK: primaryKey({
- columns: [authenticator.userId, authenticator.credentialID],
- }),
- })
-)
+ (authenticator) => [
+ {
+ compositePK: primaryKey({
+ columns: [authenticator.userId, authenticator.credentialID],
+ }),
+ },
+ ],
+);
```
diff --git a/docs/pages/getting-started/adapters/prisma.mdx b/docs/pages/getting-started/adapters/prisma.mdx
index ece278073e..2c79e7bf9e 100644
--- a/docs/pages/getting-started/adapters/prisma.mdx
+++ b/docs/pages/getting-started/adapters/prisma.mdx
@@ -523,7 +523,7 @@ This will create an SQL migration file and execute it:
npm exec prisma migrate dev
```
-Note that you will need to specify your database 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. Note Prisma doesn't support `.env.local` syntax, it must be named `.env`. For more information, check out their [environment variables docs](https://www.prisma.io/docs/orm/more/development-environment/environment-variables/using-multiple-env-files).
+Note that you will need to specify your database 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.
### Generate Prisma Client
diff --git a/docs/pages/getting-started/authentication/credentials.mdx b/docs/pages/getting-started/authentication/credentials.mdx
index dec604d2ae..a30b4fe5f0 100644
--- a/docs/pages/getting-started/authentication/credentials.mdx
+++ b/docs/pages/getting-started/authentication/credentials.mdx
@@ -7,7 +7,29 @@ import { Code } from "@/components/Code"
# Credentials
-To setup Auth.js with external authentication mechanisms or simply use username and password, we need to use the `Credentials` provider. This provider is designed to forward any credentials inserted into the login form (i.e. username/password) to your authentication service via the `authorize` callback on the provider configuration.
+To setup Auth.js with any external authentication mechanisms or use a traditional username/email and password flow, we can use the `Credentials` provider. This provider is designed to forward any credentials inserted into the login form (i.e. username/password, but not limited to) to your authentication service.
+
+
+ The industry has come a long way since usernames and passwords
+ as the go-to mechanism for authenticating and authorizing users to
+ web applications. Therefore, if possible, we recommend a more modern and
+ secure authentication mechanism such as any of the [OAuth
+ providers](/getting-started/authentication/oauth), [Email Magic
+ Links](/getting-started/authentication/email), or [WebAuthn
+ (Passkeys)](/getting-started/authentication/webauthn) options instead.
+
+However, we also want to be flexible and support anything
+you deem appropriate for your application and use case,
+so there are no plans to remove this provider.
+
+
+
+
+ By default, the Credentials provider does not persist data in the database.
+ However, you can still create and save any data in your database, you just
+ have to provide the necessary logic, eg. to encrypt passwords, add
+ rate-limiting, add password reset functionality, etc.
+
@@ -44,8 +66,8 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
if (!user) {
// No user found, so this is their first attempt to login
- // meaning this is also the place you could do registration
- throw new Error("User not found.")
+ // Optionally, this is also the place you could do a user registration
+ throw new Error("Invalid credentials.")
}
// return user object with their profile data
@@ -110,7 +132,9 @@ export const { signIn, signOut, handle } = SvelteKitAuth({
user = await getUserFromDb(credentials.email, pwHash)
if (!user) {
- throw new Error("User not found.")
+ // No user found, so this is their first attempt to login
+ // Optionally, this is also the place you could do a user registration
+ throw new Error("Invalid credentials.")
}
// return JSON object with the user data
@@ -161,8 +185,8 @@ app.use(
if (!user) {
// No user found, so this is their first attempt to login
- // meaning this is also the place you could do registration
- throw new Error("User not found.")
+ // Optionally, this is also the place you could do a user registration
+ throw new Error("Invalid credentials.")
}
// return user object with the their profile data
@@ -301,19 +325,47 @@ export default component$(() => {
```
+
+
+
+```html filename="views/signin.html"
+
+
+
+
+
+ Sign In
+
+
+ Sign In
+
+
+
+```
+
+
+
-## Verifying Data with Zod
+## Validating credentials
-To improve the security of your `Credentials` provider use, we can leverage a run-time schema validation library like [Zod](https://zod.dev) to validate that the inputs match what we expect.
+Always validate the credentials server-side, i.e. by leveraging a schema validation library like [Zod](https://zod.dev).
```bash npm2yarn
npm install zod
```
-Next, we'll setup the schema and parsing in our `auth.ts` configuration file, using the `authorize` callback on the `Credentials` provider.
+Next, we'll set up the schema and parsing in our `auth.ts` configuration file, using the `authorize` callback on the `Credentials` provider.
@@ -363,7 +415,7 @@ export const { handlers, auth } = NextAuth({
user = await getUserFromDb(email, pwHash)
if (!user) {
- throw new Error("User not found.")
+ throw new Error("Invalid credentials.")
}
// return JSON object with the user data
@@ -470,7 +522,7 @@ export const { handle } = SvelteKitAuth({
user = await getUserFromDb(email, pwHash)
if (!user) {
- throw new Error("User not found.")
+ throw new Error("Invalid credentials.")
}
// return JSON object with the user data
@@ -489,24 +541,3 @@ export const { handle } = SvelteKitAuth({
-
-
+
+
+```ts filename="./auth.ts"
+import NextAuth from "next-auth"
+import Loops from "next-auth/providers/loops"
+
+export const { handlers, auth, signIn, signOut } = NextAuth({
+ providers: [
+ Loops({
+ apiKey: process.env.AUTH_LOOPS_KEY,
+ transactionalId: process.env.AUTH_LOOPS_TRANSACTIONAL_ID,
+ }),
+ ],
+})
+```
+
+
+
+
+```ts filename="./src/auth.ts"
+import SvelteKitAuth from "@auth/sveltekit"
+import Loops from "@auth/sveltekit/providers/loops"
+import {
+ AUTH_LOOPS_KEY,
+ AUTH_LOOPS_TRANSACTIONAL_ID,
+} from "$env/static/private"
+
+export const { handle, signIn, signOut } = SvelteKitAuth({
+ providers: [
+ Loops({
+ apiKey: AUTH_LOOPS_KEY,
+ transactionalId: AUTH_LOOPS_TRANSACTIONAL_ID,
+ }),
+ ],
+})
+```
+
+```ts filename="./src/hooks.server.ts"
+export { handle } from "./auth"
+```
+
+
+
+
+### Add Signin Button
+
+Next, we add a signin button somewhere in your application like the Navbar. This will send an email to the user containing the magic link to sign in.
+
+
+
+
+```tsx filename="./components/sign-in.tsx"
+import { signIn } from "../../auth.ts"
+
+export function SignIn() {
+ return (
+
+ )
+}
+```
+
+
+
+
+```ts filename="src/routes/+page.svelte"
+
+
+
+
+
+
+
+```
+
+
+
+
+### Signin
+
+Start your application, click on the signin button we just added, and you should see Auth.js built-in sign in page with the option to sign in with your email.
+A user can enter their email, click "Sign in with Loops", and receive their beautifully formatted signin email.
+Clicking on the link in the email will redirect the user to your application, landing already authenticated!
+
+
+
+
+ ```bash
+ https://example.com/api/auth/callback/frontegg
+ ```
+
+
+
+
+ ```bash
+ https://example.com/auth/callback/frontegg
+ ```
+
+
+
+
+### Environment Variables
+
+```
+AUTH_FRONTEGG_ID
+AUTH_FRONTEGG_SECRET
+AUTH_FRONTEGG_ISSUER
+```
+
+### Configuration
+
+Follow these steps:
+
+Log into the [Frontegg portal](https://portal.frontegg.com)
+
+Add the required environment variables to your `.env.local` file.
+
+```
+# Environments > Your environment > Env settings
+AUTH_FRONTEGG_ID="
+
+
+```ts filename="/auth.ts"
+import NextAuth from "next-auth"
+import Frontegg from "next-auth/providers/frontegg"
+
+export const { handlers, auth, signIn, signOut } = NextAuth({
+ providers: [Frontegg],
+})
+```
+
+
+
+
+```ts filename="/src/auth.ts"
+import { SvelteKitAuth } from "@auth/sveltekit"
+import Frontegg from "@auth/sveltekit/providers/frontegg"
+
+export const { handle, signIn, signOut } = SvelteKitAuth({
+ providers: [Frontegg],
+})
+```
+
+
+
+
+```ts filename="/src/app.ts"
+import { ExpressAuth } from "@auth/express"
+import Frontegg from "@auth/express/providers/frontegg"
+
+app.use("/auth/*", ExpressAuth({ providers: [Frontegg] }))
+```
+
+
+
diff --git a/docs/pages/getting-started/providers/loops.mdx b/docs/pages/getting-started/providers/loops.mdx
new file mode 100644
index 0000000000..77a5672f38
--- /dev/null
+++ b/docs/pages/getting-started/providers/loops.mdx
@@ -0,0 +1,103 @@
+import { Callout } from "nextra/components"
+import { Code } from "@/components/Code"
+
+
+
+# Loops Provider
+
+## Overview
+
+The Loops provider uses email to send "magic links" that contain URLs with verification tokens can be used to sign in.
+
+Adding support for signing in via email in addition to one or more OAuth services provides a way for users to sign in if they lose access to their OAuth account (e.g. if it is locked or deleted).
+
+The Loops provider can be used in conjunction with (or instead of) one or more OAuth providers.
+
+## How it works
+
+On initial sign in, a **Verification Token** is sent to the email address provided. By default this token is valid for 24 hours. If the Verification Token is used within that time (i.e. by clicking on the link in the email) an account is created for the user and they are signed in.
+
+If someone provides the email address of an _existing account_ when signing in, an email is sent and they are signed into the account associated with that email address when they follow the link in the email.
+
+
+
+### Configure AuthJS with the Loops Provider
+```ts filename="./auth.ts"
+import NextAuth from "next-auth"
+import Loops from "next-auth/providers/loops"
+
+export const { handlers, auth, signIn, signOut } = NextAuth({
+ adapter: ..., // database adapter of your choosing
+ providers: [
+ Loops({
+ apiKey: process.env.AUTH_LOOPS_KEY,
+ transactionalId: process.env.AUTH_LOOPS_TRANSACTIONAL_ID,
+ }),
+ ],
+})
+```
+
+
+
+### Configure AuthJS with the Loops Provider
+```ts filename="./src/auth.ts"
+import { SvelteKitAuth } from "@auth/sveltekit"
+import Loops from "@auth/sveltekit/providers/loops"
+import { AUTH_LOOPS_KEY, AUTH_LOOPS_TRANSACTIONAL_ID } from "@env/static/private"
+
+export const { handle, signIn, signOut } = SvelteKitAuth({
+ adapter: ..., // database adapter of your choosing
+ providers: [
+ Loops({
+ apiKey: AUTH_LOOPS_KEY,
+ transactionalId: AUTH_LOOPS_TRANSACTIONAL_ID,
+ }),
+ ],
+})
+```
+
+
+
diff --git a/docs/pages/getting-started/providers/microsoft-entra-id.mdx b/docs/pages/getting-started/providers/microsoft-entra-id.mdx
index 65307b1248..b50db46ca2 100644
--- a/docs/pages/getting-started/providers/microsoft-entra-id.mdx
+++ b/docs/pages/getting-started/providers/microsoft-entra-id.mdx
@@ -54,7 +54,7 @@ https://example.com/auth/callback/microsoft-entra-id
```
AUTH_MICROSOFT_ENTRA_ID_ID
AUTH_MICROSOFT_ENTRA_ID_SECRET
-AUTH_MICROSOFT_ENTRA_ID_TENANT_ID
+AUTH_MICROSOFT_ENTRA_ID_ISSUER
```
### Configuration
@@ -71,7 +71,7 @@ const { handlers, auth, signIn, signOut } = NextAuth({
MicrosoftEntraID({
clientId: process.env.AUTH_MICROSOFT_ENTRA_ID_ID,
clientSecret: process.env.AUTH_MICROSOFT_ENTRA_ID_SECRET,
- tenantId: process.env.AUTH_MICROSOFT_ENTRA_ID_TENANT_ID,
+ issuer: process.env.AUTH_MICROSOFT_ENTRA_ID_ISSUER,
}),
],
})
@@ -90,7 +90,7 @@ export const { onRequest, useSession, useSignIn, useSignOut } = QwikAuth$(
Entra({
clientId: import.meta.env.AUTH_MICROSOFT_ENTRA_ID_ID,
clientSecret: import.meta.env.AUTH_MICROSOFT_ENTRA_ID_SECRET,
- tenantId: import.meta.env.AUTH_MICROSOFT_ENTRA_ID_TENANT_ID,
+ issuer: import.meta.env.AUTH_MICROSOFT_ENTRA_ID_ISSUER,
}),
],
})
@@ -110,7 +110,7 @@ export const { handle, signIn, signOut } = SvelteKitAuth({
Entra({
clientId: env.AUTH_MICROSOFT_ENTRA_ID_ID,
clientSecret: env.AUTH_MICROSOFT_ENTRA_ID_SECRET,
- tenantId: process.env.AUTH_MICROSOFT_ENTRA_ID_TENANT_ID,
+ issuer: process.env.AUTH_MICROSOFT_ENTRA_ID_ISSUER,
}),
],
})
@@ -130,7 +130,7 @@ app.use(
Entra({
clientId: process.env.AUTH_MICROSOFT_ENTRA_ID_ID,
clientSecret: process.env.AUTH_MICROSOFT_ENTRA_ID_SECRET,
- tenantId: process.env.AUTH_MICROSOFT_ENTRA_ID_TENANT_ID,
+ issuer: process.env.AUTH_MICROSOFT_ENTRA_ID_ISSUER,
}),
],
})
@@ -153,15 +153,15 @@ app.use(
- After your App Registration is created, under "Client Credential" create your Client secret.
- Now copy your:
- Application (client) ID
- - Directory (tenant) ID
- Client secret (value)
+ - Issuer
In `.env.local` create the following entries:
```
AUTH_MICROSOFT_ENTRA_ID_ID=
+
+
+```bash
+https://example.com/api/auth/callback/vipps
+```
+
+
+
+
+```bash
+https://example.com/auth/callback/vipps
+```
+
+
+
+
+```bash
+https://example.com/auth/callback/vipps
+```
+
+
+
+
+### Environment Variables
+
+```
+AUTH_VIPPS_ID
+AUTH_VIPPS_SECRET
+```
+
+### Test API
+
+To use the test mode, you need to override the issuer with the test API endpoint.
+
+```
+Vipps({ issuer: "https://apitest.vipps.no/access-management-1.0/access/" })
+```
+
+### Configuration
+
+
+
+
+```ts filename="/auth.ts"
+import NextAuth from "next-auth"
+import Vipps from "next-auth/providers/vipps"
+
+export const { handlers, auth, signIn, signOut } = NextAuth({
+ providers: [Vipps],
+})
+```
+
+
+
+
+```ts filename="/src/routes/plugin@auth.ts"
+import { QwikAuth$ } from "@auth/qwik"
+import Vipps from "@auth/qwik/providers/vipps"
+
+export const { onRequest, useSession, useSignIn, useSignOut } = QwikAuth$(
+ () => ({
+ providers: [Vipps],
+ })
+)
+```
+
+
+
+
+```ts filename="/src/auth.ts"
+import { SvelteKitAuth } from "@auth/sveltekit"
+import Vipps from "@auth/sveltekit/providers/vipps"
+
+export const { handle, signIn, signOut } = SvelteKitAuth({
+ providers: [Vipps],
+})
+```
+
+
+
+
+```ts filename="/src/app.ts"
+import { ExpressAuth } from "@auth/express"
+import Vipps from "@auth/express/providers/vipps"
+
+app.use("/auth/*", ExpressAuth({ providers: [Vipps] }))
+```
+
+
+
diff --git a/docs/pages/getting-started/session-management/get-session.mdx b/docs/pages/getting-started/session-management/get-session.mdx
index 392b08235a..85909f365f 100644
--- a/docs/pages/getting-started/session-management/get-session.mdx
+++ b/docs/pages/getting-started/session-management/get-session.mdx
@@ -14,7 +14,7 @@ import { auth } from "../auth"
export default async function UserAvatar() {
const session = await auth()
- if (!session.user) return null
+ if (!session?.user) return null
return (
{session}+
{JSON.stringify(session, null, 2)}