From 8f38c82ed7651d5c1e905e265ab1deb835826ce1 Mon Sep 17 00:00:00 2001 From: Thomas Schuster Date: Sun, 26 May 2024 16:50:03 +0200 Subject: [PATCH 1/6] add azure ad authentication --- .env.sample | 14 +++++++- pages/api/v1/auth/[...nextauth].ts | 55 +++++++++++++++++++++++++----- pages/api/v1/logins/index.ts | 13 +++++++ types/enviornment.d.ts | 14 ++++++-- 4 files changed, 84 insertions(+), 12 deletions(-) diff --git a/.env.sample b/.env.sample index 30bc044..39b037b 100644 --- a/.env.sample +++ b/.env.sample @@ -84,7 +84,6 @@ AUTHELIA_CLIENT_ID="" AUTHELIA_CLIENT_SECRET="" AUTHELIA_WELLKNOWN_URL="" - # Authentik NEXT_PUBLIC_AUTHENTIK_ENABLED= AUTHENTIK_CUSTOM_NAME= @@ -92,6 +91,19 @@ AUTHENTIK_ISSUER= AUTHENTIK_CLIENT_ID= AUTHENTIK_CLIENT_SECRET= +# Azure AD B2C +NEXT_PUBLIC_AZURE_AD_B2C_ENABLED= +AZURE_AD_B2C_TENANT_NAME= +AZURE_AD_B2C_CLIENT_ID= +AZURE_AD_B2C_CLIENT_SECRET= +AZURE_AD_B2C_PRIMARY_USER_FLOW= + +# Azure AD +NEXT_PUBLIC_AZURE_AD_ENABLED= +AZURE_AD_CLIENT_ID= +AZURE_AD_CLIENT_SECRET= +AZURE_AD_TENANT_ID= + # Battle.net NEXT_PUBLIC_BATTLENET_ENABLED= BATTLENET_CUSTOM_NAME= diff --git a/pages/api/v1/auth/[...nextauth].ts b/pages/api/v1/auth/[...nextauth].ts index 91fe7a7..dfb69ef 100644 --- a/pages/api/v1/auth/[...nextauth].ts +++ b/pages/api/v1/auth/[...nextauth].ts @@ -1,27 +1,31 @@ import { prisma } from "@/lib/api/db"; -import NextAuth from "next-auth/next"; -import CredentialsProvider from "next-auth/providers/credentials"; -import bcrypt from "bcrypt"; -import EmailProvider from "next-auth/providers/email"; -import { PrismaAdapter } from "@auth/prisma-adapter"; -import { Adapter } from "next-auth/adapters"; import sendVerificationRequest from "@/lib/api/sendVerificationRequest"; -import { Provider } from "next-auth/providers"; import verifySubscription from "@/lib/api/verifySubscription"; +import { PrismaAdapter } from "@auth/prisma-adapter"; +import bcrypt from "bcrypt"; +import { randomBytes } from "crypto"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { Adapter } from "next-auth/adapters"; +import NextAuth from "next-auth/next"; +import { Provider } from "next-auth/providers"; import FortyTwoProvider from "next-auth/providers/42-school"; import AppleProvider from "next-auth/providers/apple"; import AtlassianProvider from "next-auth/providers/atlassian"; import Auth0Provider from "next-auth/providers/auth0"; import AuthentikProvider from "next-auth/providers/authentik"; +import AzureAdProvider from "next-auth/providers/azure-ad"; +import AzureAdB2CProvider from "next-auth/providers/azure-ad-b2c"; import BattleNetProvider, { BattleNetIssuer, } from "next-auth/providers/battlenet"; import BoxProvider from "next-auth/providers/box"; import CognitoProvider from "next-auth/providers/cognito"; import CoinbaseProvider from "next-auth/providers/coinbase"; +import CredentialsProvider from "next-auth/providers/credentials"; import DiscordProvider from "next-auth/providers/discord"; import DropboxProvider from "next-auth/providers/dropbox"; import DuendeIDS6Provider from "next-auth/providers/duende-identity-server6"; +import EmailProvider from "next-auth/providers/email"; import EVEOnlineProvider from "next-auth/providers/eveonline"; import FacebookProvider from "next-auth/providers/facebook"; import FaceItProvider from "next-auth/providers/faceit"; @@ -64,8 +68,6 @@ import ZitadelProvider from "next-auth/providers/zitadel"; import ZohoProvider from "next-auth/providers/zoho"; import ZoomProvider from "next-auth/providers/zoom"; import * as process from "process"; -import type { NextApiRequest, NextApiResponse } from "next"; -import { randomBytes } from "crypto"; const emailEnabled = process.env.EMAIL_FROM && process.env.EMAIL_SERVER ? true : false; @@ -354,6 +356,41 @@ if (process.env.NEXT_PUBLIC_AUTHENTIK_ENABLED === "true") { }; } +// Azure AD B2C +if (process.env.NEXT_PUBLIC_AZURE_AD_ENABLED === "true") { + providers.push( + AzureAdB2CProvider({ + tenantId: process.env.AZURE_AD_B2C_TENANT_NAME, + clientId: process.env.AZURE_AD_B2C_CLIENT_ID!, + clientSecret: process.env.AZURE_AD_B2C_CLIENT_SECRET!, + primaryUserFlow: process.env.AZURE_AD_B2C_PRIMARY_USER_FLOW, + authorization: { params: { scope: "offline_access openid" } }, + }) + ); + + const _linkAccount = adapter.linkAccount; + adapter.linkAccount = (account) => { + const { "not-before-policy": _, refresh_expires_in, ...data } = account; + return _linkAccount ? _linkAccount(data) : undefined; + }; + +// Azure AD +if (process.env.NEXT_PUBLIC_AZURE_AD_ENABLED === "true") { + providers.push( + AzureAdProvider({ + clientId: process.env.AZURE_AD_CLIENT_ID!, + clientSecret: process.env.AZURE_AD_CLIENT_SECRET!, + tenantId: process.env.AZURE_AD_TENANT_ID, + }) + ); + + const _linkAccount = adapter.linkAccount; + adapter.linkAccount = (account) => { + const { "not-before-policy": _, refresh_expires_in, ...data } = account; + return _linkAccount ? _linkAccount(data) : undefined; + }; +} + // Battle.net if (process.env.NEXT_PUBLIC_BATTLENET_ENABLED === "true") { providers.push( diff --git a/pages/api/v1/logins/index.ts b/pages/api/v1/logins/index.ts index d2ac875..6d2c998 100644 --- a/pages/api/v1/logins/index.ts +++ b/pages/api/v1/logins/index.ts @@ -55,6 +55,19 @@ export function getLogins() { name: process.env.AUTHENTIK_CUSTOM_NAME ?? "Authentik", }); } + // Azure AD B2C + if (process.env.NEXT_PUBLIC_AZURE_AD_B2C_ENABLED === "true") { + buttonAuths.push({ + method: "azure-ad-b2c", + name: process.env.AUTHENTIK_CUSTOM_NAME ?? "Azure AD B2C", + }); + // Azure AD + if (process.env.NEXT_PUBLIC_AZURE_AD_ENABLED === "true") { + buttonAuths.push({ + method: "azure-ad", + name: process.env.AUTHENTIK_CUSTOM_NAME ?? "Azure AD", + }); + } // Battle.net if (process.env.NEXT_PUBLIC_BATTLENET_ENABLED === "true") { buttonAuths.push({ diff --git a/types/enviornment.d.ts b/types/enviornment.d.ts index 32bc29d..575a491 100644 --- a/types/enviornment.d.ts +++ b/types/enviornment.d.ts @@ -93,8 +93,18 @@ declare global { AUTHENTIK_CLIENT_ID?: string; AUTHENTIK_CLIENT_SECRET?: string; - // TODO: Azure AD B2C - // TODO: Azure AD + // Azure AD B2C + NEXT_PUBLIC_AZURE_AD_B2C_ENABLED?: string; + AZURE_AD_B2C_TENANT_NAME?: string; + AZURE_AD_B2C_CLIENT_ID?: string; + AZURE_AD_B2C_CLIENT_SECRET?: string; + AZURE_AD_B2C_PRIMARY_USER_FLOW?: string; + + // Azure AD + NEXT_PUBLIC_AZURE_AD_ENABLED?: string; + AZURE_AD_CLIENT_ID?: string; + AZURE_AD_CLIENT_SECRET?: string; + AZURE_AD_TENANT_ID?: string; // Battle.net NEXT_PUBLIC_BATTLENET_ENABLED?: string; From fc97735703254849edacda38634b07e8db9b3f9c Mon Sep 17 00:00:00 2001 From: Thomas Schuster Date: Sun, 26 May 2024 16:50:55 +0200 Subject: [PATCH 2/6] fix battlenet typo --- .env.sample | 2 +- pages/api/v1/auth/[...nextauth].ts | 2 +- types/enviornment.d.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.env.sample b/.env.sample index 39b037b..013481d 100644 --- a/.env.sample +++ b/.env.sample @@ -109,7 +109,7 @@ NEXT_PUBLIC_BATTLENET_ENABLED= BATTLENET_CUSTOM_NAME= BATTLENET_CLIENT_ID= BATTLENET_CLIENT_SECRET= -BATLLENET_ISSUER= +BATTLENET_ISSUER= # Box NEXT_PUBLIC_BOX_ENABLED= diff --git a/pages/api/v1/auth/[...nextauth].ts b/pages/api/v1/auth/[...nextauth].ts index dfb69ef..adbd457 100644 --- a/pages/api/v1/auth/[...nextauth].ts +++ b/pages/api/v1/auth/[...nextauth].ts @@ -397,7 +397,7 @@ if (process.env.NEXT_PUBLIC_BATTLENET_ENABLED === "true") { BattleNetProvider({ clientId: process.env.BATTLENET_CLIENT_ID!, clientSecret: process.env.BATTLENET_CLIENT_SECRET!, - issuer: process.env.BATLLENET_ISSUER as BattleNetIssuer, + issuer: process.env.BATTLENET_ISSUER as BattleNetIssuer, }) ); diff --git a/types/enviornment.d.ts b/types/enviornment.d.ts index 575a491..f24b1f3 100644 --- a/types/enviornment.d.ts +++ b/types/enviornment.d.ts @@ -111,7 +111,7 @@ declare global { BATTLENET_CUSTOM_NAME?: string; BATTLENET_CLIENT_ID?: string; BATTLENET_CLIENT_SECRET?: string; - BATLLENET_ISSUER?: string; + BATTLENET_ISSUER?: string; // Box NEXT_PUBLIC_BOX_ENABLED?: string; From bc3ec3cc54c47a0cfbc79c5ccb27c48cf41e90df Mon Sep 17 00:00:00 2001 From: Thomas Schuster Date: Sun, 26 May 2024 16:52:53 +0200 Subject: [PATCH 3/6] fix small mistakes --- pages/api/v1/auth/[...nextauth].ts | 1 + pages/api/v1/logins/index.ts | 5 +++-- types/enviornment.d.ts | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pages/api/v1/auth/[...nextauth].ts b/pages/api/v1/auth/[...nextauth].ts index adbd457..e6af507 100644 --- a/pages/api/v1/auth/[...nextauth].ts +++ b/pages/api/v1/auth/[...nextauth].ts @@ -373,6 +373,7 @@ if (process.env.NEXT_PUBLIC_AZURE_AD_ENABLED === "true") { const { "not-before-policy": _, refresh_expires_in, ...data } = account; return _linkAccount ? _linkAccount(data) : undefined; }; +} // Azure AD if (process.env.NEXT_PUBLIC_AZURE_AD_ENABLED === "true") { diff --git a/pages/api/v1/logins/index.ts b/pages/api/v1/logins/index.ts index 6d2c998..7e290af 100644 --- a/pages/api/v1/logins/index.ts +++ b/pages/api/v1/logins/index.ts @@ -59,13 +59,14 @@ export function getLogins() { if (process.env.NEXT_PUBLIC_AZURE_AD_B2C_ENABLED === "true") { buttonAuths.push({ method: "azure-ad-b2c", - name: process.env.AUTHENTIK_CUSTOM_NAME ?? "Azure AD B2C", + name: process.env.AZURE_AD_B2C_CUSTOM_NAME ?? "Azure AD B2C", }); + } // Azure AD if (process.env.NEXT_PUBLIC_AZURE_AD_ENABLED === "true") { buttonAuths.push({ method: "azure-ad", - name: process.env.AUTHENTIK_CUSTOM_NAME ?? "Azure AD", + name: process.env.AZURE_AD_CUSTOM_NAME ?? "Azure AD", }); } // Battle.net diff --git a/types/enviornment.d.ts b/types/enviornment.d.ts index f24b1f3..a1af24f 100644 --- a/types/enviornment.d.ts +++ b/types/enviornment.d.ts @@ -95,6 +95,7 @@ declare global { // Azure AD B2C NEXT_PUBLIC_AZURE_AD_B2C_ENABLED?: string; + AZURE_AD_B2C_CUSTOM_NAME?: string; AZURE_AD_B2C_TENANT_NAME?: string; AZURE_AD_B2C_CLIENT_ID?: string; AZURE_AD_B2C_CLIENT_SECRET?: string; @@ -102,6 +103,7 @@ declare global { // Azure AD NEXT_PUBLIC_AZURE_AD_ENABLED?: string; + AZURE_AD_CUSTOM_NAME?: string; AZURE_AD_CLIENT_ID?: string; AZURE_AD_CLIENT_SECRET?: string; AZURE_AD_TENANT_ID?: string; From 4344183564905733a5f409939a96cf18424bc23e Mon Sep 17 00:00:00 2001 From: Thomas Schuster Date: Sun, 26 May 2024 17:30:49 +0200 Subject: [PATCH 4/6] fix build error --- pages/confirmation.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pages/confirmation.tsx b/pages/confirmation.tsx index f8f99b6..0a5641b 100644 --- a/pages/confirmation.tsx +++ b/pages/confirmation.tsx @@ -1,8 +1,7 @@ import CenteredForm from "@/layouts/CenteredForm"; import { signIn } from "next-auth/react"; -import Link from "next/link"; import { useRouter } from "next/router"; -import React, { useState } from "react"; +import { useState } from "react"; import toast from "react-hot-toast"; export default function EmailConfirmaion() { @@ -38,8 +37,8 @@ export default function EmailConfirmaion() {

- A sign in link has been sent to your email address. If you don't see - the email, check your spam folder. + A sign in link has been sent to your email address. If you don&apost + see the email, check your spam folder.

From 5f34f03355b7e742a6cd95e86ee193b48ad7c2d5 Mon Sep 17 00:00:00 2001 From: Thomas Schuster Date: Sun, 26 May 2024 17:31:11 +0200 Subject: [PATCH 5/6] fix github documentation --- .env.sample | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.sample b/.env.sample index 013481d..535f294 100644 --- a/.env.sample +++ b/.env.sample @@ -198,8 +198,8 @@ FUSIONAUTH_TENANT_ID= # GitHub NEXT_PUBLIC_GITHUB_ENABLED= GITHUB_CUSTOM_NAME= -GITHUB_CLIENT_ID= -GITHUB_CLIENT_SECRET= +GITHUB_ID= +GITHUB_SECRET= # GitLab NEXT_PUBLIC_GITLAB_ENABLED= From 7e98de6122af7269f2dc3faf62942990bdb65f9b Mon Sep 17 00:00:00 2001 From: Thomas Schuster Date: Sun, 26 May 2024 17:31:22 +0200 Subject: [PATCH 6/6] fix azure errors --- pages/api/v1/auth/[...nextauth].ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/pages/api/v1/auth/[...nextauth].ts b/pages/api/v1/auth/[...nextauth].ts index e6af507..dfe717e 100644 --- a/pages/api/v1/auth/[...nextauth].ts +++ b/pages/api/v1/auth/[...nextauth].ts @@ -370,7 +370,15 @@ if (process.env.NEXT_PUBLIC_AZURE_AD_ENABLED === "true") { const _linkAccount = adapter.linkAccount; adapter.linkAccount = (account) => { - const { "not-before-policy": _, refresh_expires_in, ...data } = account; + const { + "not-before-policy": _, + refresh_expires_in, + refresh_token_expires_in, + not_before, + id_token_expires_in, + profile_info, + ...data + } = account; return _linkAccount ? _linkAccount(data) : undefined; }; } @@ -387,7 +395,15 @@ if (process.env.NEXT_PUBLIC_AZURE_AD_ENABLED === "true") { const _linkAccount = adapter.linkAccount; adapter.linkAccount = (account) => { - const { "not-before-policy": _, refresh_expires_in, ...data } = account; + const { + "not-before-policy": _, + refresh_expires_in, + token_type, + expires_in, + ext_expires_in, + access_token, + ...data + } = account; return _linkAccount ? _linkAccount(data) : undefined; }; }