diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3cdba80f..66b22152 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,76 +1,76 @@
-# Change Log
-
-## [9.1.1](https://github.com/frontegg/frontegg-nextjs/compare/v9.0.5...v9.1.1) (2024-11-12)
-
-- FR-18594 - Fixed blinking bug On IP and domain page
-- FR-18499 - Fixed otc page blink
-- FR-18005 - Fixed search api tokens with null descriptions
-- FR-18499 - Fixed activate with code and password
-- FR-18582 - Fixed loader size and wrong massage
-
-
+# Change Log
+
+## [9.2.0](https://github.com/frontegg/frontegg-nextjs/compare/v9.1.1...v9.2.0) (2024-11-25)
+
+- FR-18699 - Removed entitlements automatic 30 seconds refresh mechanism
+- FR-18138 - Added logic to improve login box and admin portal stability and resiliency
+- FR-18646 - Fixed missing permissions with wildcard on custom roles
+- FR-18341 - Fixed Google Chrome Translate feature causes a crash
+- FR-16902 - Fixed login box scroll on mobile browsers
+
+
+### NextJS Wrapper 9.2.0:
+- FR-17280 - Fixed NextJS v15 build issue
+
+## [9.1.1](https://github.com/frontegg/frontegg-nextjs/compare/v9.0.5...v9.1.1) (2024-11-12)
+
+- FR-18594 - Fixed blinking bug On IP and domain page
+- FR-18499 - Fixed otc page blink
+- FR-18005 - Fixed search api tokens with null descriptions
+- FR-18499 - Fixed activate with code and password
+- FR-18582 - Fixed loader size and wrong massage
- FR-18561 - Fixed get ip metadata when app name is provided
- FR-17091 - Fixed long name in groups and roles
-
-
-- FR-18529 - Fixed empty roles field bug when appName is provided
-
-
-- FR-18516 - Fixed redundant function
-- FR-18476 - Added url for beforeRequestInterceptor function
-
-
-- FR-18476 - Added request interceptor
-- FR-18472 - Fixed Google one tap login stuck after unmounting login/signup unmounted
-
-- FR-18436 - Fixed activate account with empty redirect bug
-
-
-- FR-17943 - Added code pages
-
-- FR-18427 - Added Support for triggering MFA after native passkeys / iOS apple login
-- FR-18211 - Fixed email overlapping roles field
-
-
-### NextJS Wrapper 9.1.1:
-- FR-17280 - fix next js 15 build & update example app project middleware
-- FR-18495 - refresh the token when it has expired
-- FR-18442 - Remove cookies when landing on oauth/callback to support after hosted login activate account succeeded
-- FR-18442 - Fix Nextjs session store injection and support SSG pages
-- Fix session abandoned when accessing not found page
-- Export FronteggAppRouterAsync to be imported by '@frontegg/nextjs/app'
-
-## [9.0.5](https://github.com/frontegg/frontegg-nextjs/compare/v9.0.4...v9.0.5) (2024-10-31)
-
-- FR-18476 - Added url for beforeRequestInterceptor function
-
-
-- FR-18476 - Added request interceptor
-- FR-18472 - Fixed Google one tap login stuck after unmounting login/signup unmounted
-
-- FR-18436 - Fixed activate account with empty redirect bug
-
-
-- FR-17943 - Added code pages
-
-- FR-18427 - Added Support for triggering MFA after native passkeys / iOS apple login
-- FR-18211 - Fixed email overlapping roles field
-
-- FR-18356 - Fixed validations localization override type
-
-
-### NextJS Wrapper 9.0.5:
-- FR-18442 - Remove cookies when landing on oauth/callback to support after hosted login activate account succeeded
-- FR-18442 - Fix Nextjs session store injection and support SSG pages
-- Fix session abandoned when accessing not found page
-- Export FronteggAppRouterAsync to be imported by '@frontegg/nextjs/app'
-- Add Support for NextJS 15
-
-## [9.0.4](https://github.com/frontegg/frontegg-nextjs/compare/v9.0.3...v9.0.4) (2024-10-22)
-
-- FR-18356 - Fixed validations localization override type
-
-
+- FR-18529 - Fixed empty roles field bug when appName is provided
+- FR-18516 - Fixed redundant function
+- FR-18476 - Added url for beforeRequestInterceptor function
+- FR-18476 - Added request interceptor
+- FR-18472 - Fixed Google one tap login stuck after unmounting login/signup unmounted
+- FR-18436 - Fixed activate account with empty redirect bug
+- FR-17943 - Added code pages
+- FR-18427 - Added Support for triggering MFA after native passkeys / iOS apple login
+- FR-18211 - Fixed email overlapping roles field
+
+
+### NextJS Wrapper 9.1.1:
+- FR-17280 - fix next js 15 build & update example app project middleware
+- FR-18495 - refresh the token when it has expired
+- FR-18442 - Remove cookies when landing on oauth/callback to support after hosted login activate account succeeded
+- FR-18442 - Fix Nextjs session store injection and support SSG pages
+- Fix session abandoned when accessing not found page
+- Export FronteggAppRouterAsync to be imported by '@frontegg/nextjs/app'
+
+## [9.0.5](https://github.com/frontegg/frontegg-nextjs/compare/v9.0.4...v9.0.5) (2024-10-31)
+
+- FR-18476 - Added url for beforeRequestInterceptor function
+
+
+- FR-18476 - Added request interceptor
+- FR-18472 - Fixed Google one tap login stuck after unmounting login/signup unmounted
+
+- FR-18436 - Fixed activate account with empty redirect bug
+
+
+- FR-17943 - Added code pages
+
+- FR-18427 - Added Support for triggering MFA after native passkeys / iOS apple login
+- FR-18211 - Fixed email overlapping roles field
+
+- FR-18356 - Fixed validations localization override type
+
+
+### NextJS Wrapper 9.0.5:
+- FR-18442 - Remove cookies when landing on oauth/callback to support after hosted login activate account succeeded
+- FR-18442 - Fix Nextjs session store injection and support SSG pages
+- Fix session abandoned when accessing not found page
+- Export FronteggAppRouterAsync to be imported by '@frontegg/nextjs/app'
+- Add Support for NextJS 15
+
+## [9.0.4](https://github.com/frontegg/frontegg-nextjs/compare/v9.0.3...v9.0.4) (2024-10-22)
+
+- FR-18356 - Fixed validations localization override type
+
+
# Change Log
## [9.0.3](https://github.com/frontegg/frontegg-nextjs/compare/v9.0.2...v9.0.3) (2024-10-10)
diff --git a/lerna.json b/lerna.json
index b5f5e70e..c51c7b3a 100755
--- a/lerna.json
+++ b/lerna.json
@@ -2,10 +2,10 @@
"packages": [
"packages/*"
],
- "version": "9.1.1",
+ "version": "9.2.0",
"npmClient": "yarn",
"publishConfig": {
"registry": "https://registry.npmjs.org",
"directory": "dist"
}
-}
\ No newline at end of file
+}
diff --git a/packages/example-app-directory/app/page.tsx b/packages/example-app-directory/app/page.tsx
index ba077825..53f3d2fb 100644
--- a/packages/example-app-directory/app/page.tsx
+++ b/packages/example-app-directory/app/page.tsx
@@ -11,8 +11,13 @@ export default function MainPage() {
check session
-
+
+
Go to SSG page
+
+
+ logout embedded
+
);
}
diff --git a/packages/example-app-directory/package.json b/packages/example-app-directory/package.json
index 6d39015e..fd3d42ab 100644
--- a/packages/example-app-directory/package.json
+++ b/packages/example-app-directory/package.json
@@ -1,6 +1,6 @@
{
"name": "@frontegg/example-app-directory",
- "version": "9.1.1",
+ "version": "9.2.0",
"private": true,
"scripts": {
"clean": "rm -rf ./node_modules && rm -rf ./.next",
diff --git a/packages/example-app-directory/pages/api/frontegg/[...frontegg-middleware].ts b/packages/example-app-directory/pages/api/frontegg/[...frontegg-middleware].ts
index 33ceb25b..bc73d1f1 100644
--- a/packages/example-app-directory/pages/api/frontegg/[...frontegg-middleware].ts
+++ b/packages/example-app-directory/pages/api/frontegg/[...frontegg-middleware].ts
@@ -1,6 +1,18 @@
import { FronteggApiMiddleware } from '@frontegg/nextjs/middleware';
export default FronteggApiMiddleware;
+
+/**
+ * Option to support multiple origins in single nextjs backend
+ *
+ * export default FronteggApiMiddleware.cors({
+ * allowedOrigins: ['http://localapp1.davidantoon.me:3000', 'http://localapp2.davidantoon.me:3000'],
+ * allowCredentials: true,
+ * allowedMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
+ * });
+ *
+ */
+
export const config = {
api: {
externalResolver: true,
diff --git a/packages/example-pages/package.json b/packages/example-pages/package.json
index 89ed9f5b..b994bd44 100644
--- a/packages/example-pages/package.json
+++ b/packages/example-pages/package.json
@@ -1,6 +1,6 @@
{
"name": "@frontegg/example-pages",
- "version": "9.1.1",
+ "version": "9.2.0",
"private": true,
"scripts": {
"clean": "rm -rf ./node_modules && rm -rf ./.next",
diff --git a/packages/example-pages/pages/api/frontegg/[...frontegg-middleware].ts b/packages/example-pages/pages/api/frontegg/[...frontegg-middleware].ts
index 968897fc..bc73d1f1 100644
--- a/packages/example-pages/pages/api/frontegg/[...frontegg-middleware].ts
+++ b/packages/example-pages/pages/api/frontegg/[...frontegg-middleware].ts
@@ -5,28 +5,12 @@ export default FronteggApiMiddleware;
/**
* Option to support multiple origins in single nextjs backend
*
- * import type { NextApiRequest, NextApiResponse } from 'next';
+ * export default FronteggApiMiddleware.cors({
+ * allowedOrigins: ['http://localapp1.davidantoon.me:3000', 'http://localapp2.davidantoon.me:3000'],
+ * allowCredentials: true,
+ * allowedMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
+ * });
*
- * export default function handler(req: NextApiRequest, res: NextApiResponse): Promise {
- * // Add CORS headers after the handler has run
- * const allowedOrigins = ['http://localapp1.davidantoon.me:3000', 'http://localapp2.davidantoon.me:3000'];
- * const origin = req.headers.origin ?? '';
- *
- * if (allowedOrigins.includes(origin)) {
- * res.setHeader('Access-Control-Allow-Origin', origin);
- * } else {
- * res.removeHeader('Access-Control-Allow-Origin');
- * }
- *
- * res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,PATCH,OPTIONS');
- * res.setHeader(
- * 'Access-Control-Allow-Headers',
- * 'Content-Type, Authorization, x-frontegg-framework, x-frontegg-sdk, frontegg-source'
- * );
- * res.setHeader('Access-Control-Allow-Credentials', 'true');
- *
- * return FronteggApiMiddleware(req, res);
- * }
*/
export const config = {
diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json
index b8c97968..f006e6ca 100644
--- a/packages/nextjs/package.json
+++ b/packages/nextjs/package.json
@@ -1,7 +1,7 @@
{
"name": "@frontegg/nextjs",
"libName": "FronteggNextJs",
- "version": "9.1.1",
+ "version": "9.2.0",
"author": "Frontegg LTD",
"license": "MIT",
"repository": {
diff --git a/packages/nextjs/src/app/FronteggAppProvider.tsx b/packages/nextjs/src/app/FronteggAppProvider.tsx
index ea099e46..347299e6 100644
--- a/packages/nextjs/src/app/FronteggAppProvider.tsx
+++ b/packages/nextjs/src/app/FronteggAppProvider.tsx
@@ -6,6 +6,8 @@ import fetchUserData from '../utils/fetchUserData';
import { ClientFronteggProviderProps } from '../types';
import { getAppUrlForCustomLoginWithSubdomain } from './getAppUrlForCustomLoginWithSubdomain';
import { removeJwtSignatureFrom } from '../middleware/helpers';
+import fronteggLogger from '../utils/fronteggLogger';
+import { FRONTEGG_HOSTED_LOGIN_MIGRATION_WARNING } from './consts';
export type FronteggAppProviderProps = PropsWithChildren<
Omit
@@ -15,17 +17,23 @@ export const FronteggAppProvider = async (options: FronteggAppProviderProps) =>
const { envAppUrl, ...appEnvConfig } = config.appEnvConfig;
let userData = await fetchUserData({ getSession: getAppSession, getHeaders: getAppHeaders });
const subDomainAppUrl = await getAppUrlForCustomLoginWithSubdomain(options.customLoginOptions?.subDomainIndex);
+ const logger = fronteggLogger.child({ tag: 'FronteggAppProvider' });
if (process.env['FRONTEGG_SECURE_JWT_ENABLED'] === 'true' && userData) {
userData = removeJwtSignatureFrom(userData);
userData.session = removeJwtSignatureFrom(userData?.session);
}
+ if (Object.hasOwn(options, 'hostedLoginBox')) {
+ logger.warn(FRONTEGG_HOSTED_LOGIN_MIGRATION_WARNING);
+ }
+
const providerProps = {
...appEnvConfig,
...userData,
...options,
envAppUrl: subDomainAppUrl ?? envAppUrl,
secureJwtEnabled: options.secureJwtEnabled ?? false,
+ hostedLoginBox: appEnvConfig.envHostedLoginBox ?? options.hostedLoginBox ?? false,
};
return ;
diff --git a/packages/nextjs/src/app/consts.ts b/packages/nextjs/src/app/consts.ts
new file mode 100644
index 00000000..3cabb16b
--- /dev/null
+++ b/packages/nextjs/src/app/consts.ts
@@ -0,0 +1 @@
+export const FRONTEGG_HOSTED_LOGIN_MIGRATION_WARNING = `\n**Deprecated**: The 'hostedLoginBox' prop is deprecated in frontegg NextJS SKD and will be removed in the next major version. Please use 'FRONTEGG_HOSTED_LOGIN' environment variable instead.`;
diff --git a/packages/nextjs/src/edge/getSessionOnEdge.ts b/packages/nextjs/src/edge/getSessionOnEdge.ts
index a817f567..75b6d0b6 100644
--- a/packages/nextjs/src/edge/getSessionOnEdge.ts
+++ b/packages/nextjs/src/edge/getSessionOnEdge.ts
@@ -1,5 +1,5 @@
import type { IncomingMessage } from 'http';
-import { FronteggEdgeSession } from '../types';
+import { FronteggEdgeSession, FronteggNextJSSession } from '../types';
import CookieManager from '../utils/cookies';
import createSession from '../utils/createSession';
import encryptionEdge from '../utils/encryption-edge';
@@ -40,12 +40,15 @@ export const handleSessionOnEdge = async (params: HandleSessionOnEdge): Promise<
if (edgeSession.headers) {
return NextResponse.next({
headers: edgeSession.headers,
+ request: {
+ headers: edgeSession.forwardedHeaders,
+ },
});
}
return NextResponse.next();
};
-const GET_SESSION_ON_EDGE_DEPRECATED_ERROR = `Deprecation Notice: getSessionOnEdge has been deprecated. Please use handleSessionOnEdge instead. For example:
+const GET_SESSION_ON_EDGE_DEPRECATED_WARN = `Deprecation Notice: getSessionOnEdge has been deprecated. Please use handleSessionOnEdge instead. For example:
file: middleware.ts
\`\`\`ts
@@ -93,8 +96,17 @@ Alternatively, to manually verify the session, you can use checkSessionOnEdge. N
* ```
* @deprecated
*/
-export const getSessionOnEdge = async (req: IncomingMessage | Request): Promise => {
- throw new Error(GET_SESSION_ON_EDGE_DEPRECATED_ERROR);
+
+export const getSessionOnEdge = (
+ req: IncomingMessage | Request,
+ disableWarning = false
+): Promise => {
+ const logger = fronteggLogger.child({ tag: 'EdgeRuntime.getSessionOnEdge' });
+ const cookies = CookieManager.getSessionCookieFromRequest(req);
+ if (!disableWarning) {
+ logger.info(GET_SESSION_ON_EDGE_DEPRECATED_WARN);
+ }
+ return createSession(cookies, encryptionEdge);
};
/**
@@ -128,11 +140,14 @@ export const getSessionOnEdge = async (req: IncomingMessage | Request): Promise<
* return redirectToLogin(pathname);
* }
*
- * // if headers are present return them to the next response
+ * // if headers are present forward them to the next response / request
* if (session.headers) {
- * return NextResponse.next({
- * headers: session.headers,
- * });
+ * return NextResponse.next({
+ * headers: edgeSession.headers,
+ * request:{
+ * headers: edgeSession.forwardedHeaders
+ * }
+ * });
* }
* return NextResponse.next();
* };
diff --git a/packages/nextjs/src/edge/refreshAccessTokenIfNeededOnEdge.ts b/packages/nextjs/src/edge/refreshAccessTokenIfNeededOnEdge.ts
index 128f1745..80acef9e 100644
--- a/packages/nextjs/src/edge/refreshAccessTokenIfNeededOnEdge.ts
+++ b/packages/nextjs/src/edge/refreshAccessTokenIfNeededOnEdge.ts
@@ -88,6 +88,12 @@ export async function refreshAccessTokenIfNeededOnEdge(
});
newSetCookie.push(...cookieValue);
+ const forwardedHeaders = req.headers as Headers;
+ newSetCookie.forEach((cookie) => {
+ // get cookie name and value only
+ const [name, value] = cookie.split(';')[0].split('=');
+ forwardedHeaders.set('cookie', `${name}=${value}`);
+ });
return {
session: {
accessToken: data.accessToken ?? data.access_token,
@@ -97,6 +103,7 @@ export async function refreshAccessTokenIfNeededOnEdge(
headers: {
'set-cookie': newSetCookie.join(', '),
},
+ forwardedHeaders,
};
}
diff --git a/packages/nextjs/src/middleware/FronteggApiMiddleware.ts b/packages/nextjs/src/middleware/FronteggApiMiddleware.ts
index 77292e81..b0ca28c5 100644
--- a/packages/nextjs/src/middleware/FronteggApiMiddleware.ts
+++ b/packages/nextjs/src/middleware/FronteggApiMiddleware.ts
@@ -1,8 +1,9 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { FronteggProxy } from './FronteggProxy';
-import { fronteggSSOPathRewrite, fronteggPathRewrite } from './constants';
-import { rewritePath } from './helpers';
+import { fronteggSSOPathRewrite, fronteggPathRewrite, defaultFronteggHeaders } from './constants';
+import { isInternalRequest, rewritePath } from './helpers';
import { getSession } from '../pages';
+import { CorsOptions, FronteggApiMiddlewareType } from './types';
const middlewarePromise = (req: NextApiRequest, res: NextApiResponse) =>
new Promise(async (resolve) => {
@@ -36,6 +37,39 @@ const middlewarePromise = (req: NextApiRequest, res: NextApiResponse) =>
* @param {NextApiRequest} req - NextJS api request passed from api routing
* @param {NextApiResponse} res - NextJS api response passed from api routing
*/
-export async function FronteggApiMiddleware(req: NextApiRequest, res: NextApiResponse) {
+const FronteggApiMiddleware: FronteggApiMiddlewareType = (async (
+ req: NextApiRequest,
+ res: NextApiResponse
+): Promise => {
return await middlewarePromise(req, res);
-}
+}) as FronteggApiMiddlewareType;
+
+FronteggApiMiddleware.cors =
+ (options: CorsOptions) =>
+ async (req: NextApiRequest, res: NextApiResponse): Promise => {
+ const {
+ allowedOrigins = ['*'],
+ allowedMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
+ allowedHeaders = ['Content-Type', 'Authorization'],
+ allowCredentials = true,
+ } = options;
+
+ if (isInternalRequest(req.headers.host ?? '')) {
+ const origin = req.headers.origin ?? '';
+ const combinedHeaders = Array.from(new Set([...defaultFronteggHeaders, ...allowedHeaders]));
+
+ if (allowedOrigins.includes(origin)) {
+ res.setHeader('Access-Control-Allow-Origin', origin);
+ } else {
+ res.removeHeader('Access-Control-Allow-Origin');
+ }
+
+ res.setHeader('Access-Control-Allow-Methods', allowedMethods.join(','));
+ res.setHeader('Access-Control-Allow-Headers', combinedHeaders.join(','));
+ res.setHeader('Access-Control-Allow-Credentials', allowCredentials ? 'true' : 'false');
+ }
+
+ return middlewarePromise(req, res);
+ };
+
+export { FronteggApiMiddleware };
diff --git a/packages/nextjs/src/middleware/constants.ts b/packages/nextjs/src/middleware/constants.ts
index f43354fa..05841b89 100644
--- a/packages/nextjs/src/middleware/constants.ts
+++ b/packages/nextjs/src/middleware/constants.ts
@@ -10,3 +10,12 @@ export const fronteggSSOPathRewrite = [
replaceStr: '/auth/saml/callback',
},
];
+
+export const defaultFronteggHeaders = [
+ 'Content-Type',
+ 'Authorization',
+ 'x-frontegg-framework',
+ 'x-frontegg-sdk',
+ 'frontegg-source',
+ 'frontegg-requested-application-id',
+];
diff --git a/packages/nextjs/src/middleware/helpers.ts b/packages/nextjs/src/middleware/helpers.ts
index 387d1709..05c1112a 100644
--- a/packages/nextjs/src/middleware/helpers.ts
+++ b/packages/nextjs/src/middleware/helpers.ts
@@ -119,3 +119,5 @@ export const removeJwtSignatureFrom = (body: any): T => {
});
return body;
};
+
+export const isInternalRequest = (host: string) => config.appUrl.includes(host);
diff --git a/packages/nextjs/src/middleware/types.ts b/packages/nextjs/src/middleware/types.ts
new file mode 100644
index 00000000..523378ae
--- /dev/null
+++ b/packages/nextjs/src/middleware/types.ts
@@ -0,0 +1,12 @@
+import type { NextApiRequest, NextApiResponse } from 'next';
+
+export type CorsOptions = {
+ allowedOrigins?: string[];
+ allowedMethods?: string[];
+ allowedHeaders?: string[];
+ allowCredentials?: boolean;
+};
+
+export type FronteggApiMiddlewareType = ((req: NextApiRequest, res: NextApiResponse) => Promise) & {
+ cors: (options: CorsOptions) => (req: NextApiRequest, res: NextApiResponse) => Promise;
+};
diff --git a/packages/nextjs/src/sdkVersion.ts b/packages/nextjs/src/sdkVersion.ts
index 39fa4297..1aaa08cd 100644
--- a/packages/nextjs/src/sdkVersion.ts
+++ b/packages/nextjs/src/sdkVersion.ts
@@ -1 +1 @@
-export default { version: '9.1.1' };
+export default { version: '9.2.0' };
diff --git a/packages/nextjs/src/types/index.ts b/packages/nextjs/src/types/index.ts
index 01e361b1..ee9ac51a 100644
--- a/packages/nextjs/src/types/index.ts
+++ b/packages/nextjs/src/types/index.ts
@@ -23,6 +23,7 @@ export interface FronteggNextJSSession extends FronteggUserTokens {
export interface FronteggEdgeSession {
session?: FronteggNextJSSession;
headers?: Record;
+ forwardedHeaders?: Headers;
}
export type RequestType = IncomingMessage | Request;