Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/nextjs-thunder-v2-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@asgardeo/react': minor
'@asgardeo/nextjs': minor
---

Add Thunder V2 platform compatibility to the Next.js SDK.

- Exported `SignInV2` and `SignUpV2` components from the React package.
- Updated Next.js `AsgardeoProvider` to correctly pass the `platform` and provide `FlowMetaProvider`.
- Modified Next.js `SignIn` and `SignUp` to dynamically route to V2 components when the `AsgardeoV2` platform is configured.
2 changes: 1 addition & 1 deletion packages/nextjs/src/AsgardeoNextClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class AsgardeoNextClient<T extends AsgardeoNextConfig = AsgardeoNextConfig> exte
baseUrl,
clientId,
clientSecret,
enablePKCE: false,
enablePKCE: !clientSecret,
organizationHandle: resolvedOrganizationHandle,
signInUrl,
signUpUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,26 @@ import {
EmbeddedSignInFlowHandleRequestPayload,
EmbeddedSignInFlowHandleResponse,
EmbeddedSignInFlowInitiateResponse,
Platform,
} from '@asgardeo/node';
import {BaseSignIn, BaseSignInProps} from '@asgardeo/react';
import {FC} from 'react';
import {BaseSignIn, BaseSignInProps, SignInV2, SignInRenderProps} from '@asgardeo/react';
import {FC, ReactElement} from 'react';
import useAsgardeo from '../../../contexts/Asgardeo/useAsgardeo';

/**
* Props for the SignIn component.
* Extends BaseSignInProps for full compatibility with the React BaseSignIn component
*/
export type SignInProps = Pick<BaseSignInProps, 'className' | 'onSuccess' | 'onError' | 'variant' | 'size'>;
export type SignInProps = Pick<BaseSignInProps, 'className' | 'onSuccess' | 'onError' | 'variant' | 'size'> & {
/**
* Render function for custom UI (render props pattern).
*/
children?: (props: SignInRenderProps) => ReactElement;
/**
* Component-level preferences to override global i18n and theme settings.
*/
preferences?: any;
};

/**
* A SignIn component for Next.js that provides native authentication flow.
Expand Down Expand Up @@ -78,8 +88,8 @@ export type SignInProps = Pick<BaseSignInProps, 'className' | 'onSuccess' | 'onE
* };
* ```
*/
const SignIn: FC<SignInProps> = ({size = 'medium', variant = 'outlined', ...rest}: SignInProps) => {
const {signIn, afterSignInUrl} = useAsgardeo();
const SignIn: FC<SignInProps> = ({className, size = 'medium', variant = 'outlined', children, preferences, ...rest}: SignInProps) => {
const {signIn, afterSignInUrl, platform} = useAsgardeo();

const handleInitialize = async (): Promise<EmbeddedSignInFlowInitiateResponse> =>
signIn &&
Expand All @@ -106,14 +116,31 @@ const SignIn: FC<SignInProps> = ({size = 'medium', variant = 'outlined', ...rest
return (await signIn(payload, request)) as Promise<EmbeddedSignInFlowHandleResponse>;
};

if (platform === Platform.AsgardeoV2) {
return (
<SignInV2
className={className}
size={size}
variant={variant}
onSuccess={rest.onSuccess}
onError={rest.onError}
preferences={preferences}
>
{children}
</SignInV2>
);
}

return (
<BaseSignIn
// isLoading={isLoading || !isInitialized}
afterSignInUrl={afterSignInUrl}
onInitialize={handleInitialize}
onSubmit={handleOnSubmit}
className={className}
size={size}
variant={variant}
preferences={preferences}
{...rest}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,18 @@ import {
EmbeddedFlowExecuteRequestPayload,
EmbeddedFlowExecuteResponse,
EmbeddedFlowType,
Platform,
} from '@asgardeo/node';
import {BaseSignUp, BaseSignUpProps} from '@asgardeo/react';
import {FC} from 'react';
import {BaseSignUp, BaseSignUpProps, SignUpV2, SignUpRenderProps} from '@asgardeo/react';
import {FC, ReactElement} from 'react';
import useAsgardeo from '../../../contexts/Asgardeo/useAsgardeo';

/**
* Props for the SignUp component.
*/
export type SignUpProps = BaseSignUpProps;
export type SignUpProps = Pick<BaseSignUpProps, 'className' | 'afterSignUpUrl' | 'onError' | 'variant' | 'size'> & {
children?: (props: any) => ReactElement;
};
Comment on lines +35 to +37
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify whether current repo callsites use callbacks now excluded by narrowed SignUpProps.
rg -nP --type=tsx -C2 '<SignUp[^>]*(onSuccess|onComplete|onInitialize|onSubmit)\s*='

# Inspect current exported SignUpProps definition.
rg -n -C3 'export type SignUpProps' packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx

Repository: asgardeo/javascript

Length of output: 91


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# First, locate and inspect the SignUp.tsx file
fd -t f "SignUp.tsx" packages/nextjs

# Get the file size
wc -l packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx

# Read the specific lines mentioned in the review
echo "=== Lines 35-37 (SignUpProps definition) ==="
sed -n '35,37p' packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx

echo "=== Lines 75-77 ==="
sed -n '75,77p' packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx

echo "=== Lines 116-127 ==="
sed -n '116,127p' packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx

echo "=== Lines 141-144 ==="
sed -n '141,144p' packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx

# Search for SignUpRenderProps definition
echo "=== Search for SignUpRenderProps ==="
rg -n "SignUpRenderProps" packages/nextjs/src/client/components/presentation/SignUp/

# Search for BaseSignUpProps definition to see all available props
echo "=== Search for BaseSignUpProps ==="
rg -n "export.*BaseSignUpProps" packages/nextjs/src/client/components/presentation/SignUp/

Repository: asgardeo/javascript

Length of output: 1290


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for BaseSignUpProps definition - might be in node_modules or imported
echo "=== Searching for BaseSignUpProps definition in react package ==="
fd -t f "index" packages/nextjs/node_modules/@asgardeo/react/dist/ | head -5

# Let's look at the actual type exports from `@asgardeo/react`
echo "=== Checking `@asgardeo/react` exports ==="
find packages/nextjs/node_modules/@asgardeo/react -name "*.d.ts" -o -name "index.ts" | head -10

# Search for usages of <SignUp component in the codebase (excluding SignUpV2)
echo "=== Searching for <SignUp usage patterns ==="
rg -n "<SignUp\b" packages/nextjs/src --type ts -A2 | head -50

# Also check examples or tests that might use SignUp
echo "=== Checking for SignUp usage in examples/tests ==="
rg -n "SignUp" packages/nextjs/examples 2>/dev/null || echo "No examples directory or no matches"

# Check if ...rest is actually passed down and what callbacks it might contain
echo "=== Full context around line 75-77 where rest is extracted ==="
sed -n '70,95p' packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx

Repository: asgardeo/javascript

Length of output: 285


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for actual <SignUp usage in the codebase
echo "=== Searching for <SignUp usage in source code ==="
rg -n "<SignUp\b" packages/nextjs/src -A3 | head -80

# Get the full function signature to see what rest contains
echo "=== Full function context around parameter destructuring ==="
sed -n '70,100p' packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx

# Check if there's documentation or types file
echo "=== Looking for type definitions in the file ==="
sed -n '1,40p' packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx

# Search for any usage of the excluded callbacks in the whole packages/nextjs directory
echo "=== Searching for onSuccess, onComplete, onInitialize, onSubmit with SignUp ==="
rg -n "(onSuccess|onComplete|onInitialize|onSubmit)" packages/nextjs/src --type ts | grep -i signup || echo "No matches found"

Repository: asgardeo/javascript

Length of output: 3247


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for imports of SignUp from packages/nextjs
echo "=== Searching for imports of SignUp component ==="
rg -n "from.*SignUp" packages/nextjs/src --type ts | grep -v "BaseSignUp\|SignUpV2\|SignUpRenderProps" | head -20

# Search in example files
echo "=== Checking example/demo files ==="
find packages/nextjs -type f \( -name "*.tsx" -o -name "*.ts" \) -path "*/example*" -o -path "*/demo*" | head -20

# Check where SignUp is exported from
echo "=== Checking barrel exports ==="
rg -n "SignUp" packages/nextjs/src/client/components/index.ts || echo "Not found"
rg -n "SignUp" packages/nextjs/src/index.ts || echo "Not found"

# Get the full context where onInitialize and onSubmit are used
echo "=== Context around lines 134-135 where callbacks are passed ==="
sed -n '87,140p' packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx

# Look for handleOnSubmit definition
echo "=== Looking for handleOnSubmit definition ==="
rg -n "handleOnSubmit" packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx -B5 -A5

Repository: asgardeo/javascript

Length of output: 3027


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Get the full JSDoc section for the SignUp component
echo "=== Full JSDoc/comments for SignUp component ==="
sed -n '39,70p' packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx

# Search for tests related to SignUp
echo "=== Searching for SignUp tests ==="
find packages/nextjs -type f \( -name "*.test.tsx" -o -name "*.test.ts" -o -name "*.spec.tsx" -o -name "*.spec.ts" \) | xargs grep -l "SignUp" 2>/dev/null || echo "No tests found mentioning SignUp"

# Check what callbacks BaseSignUp actually accepts by looking at imports/usage
echo "=== Full usage context of BaseSignUp ==="
sed -n '130,148p' packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx

# Check rest parameter - what's actually being passed
echo "=== Complete function parameters ==="
sed -n '73,78p' packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx

Repository: asgardeo/javascript

Length of output: 1690


Fix JSDoc and restore type safety for children prop.

The JSDoc example documents onSuccess and onComplete callbacks (lines 49-57), but these are not exposed in SignUpProps nor implemented in the component—they're only shown in misleading documentation. The narrowed Pick<BaseSignUpProps, ...> appears intentional, as the component handles initialization and submission internally via hardcoded callbacks passed to BaseSignUp.

However, the any type for the children prop (lines 36, 126, 143) unnecessarily drops type safety. Use SignUpRenderProps instead:

Proposed fix
 export type SignUpProps = Pick<BaseSignUpProps, 'className' | 'afterSignUpUrl' | 'onError' | 'variant' | 'size'> & {
-  children?: (props: any) => ReactElement;
+  children?: (props: SignUpRenderProps) => ReactElement;
 };

Then remove the as any casts at lines 126 and 143:

-        {children as any}
+        {children}

The JSDoc example should also be corrected to remove onSuccess and onComplete callbacks, or those callbacks should be properly implemented and exposed if they are intended to be part of the public API.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export type SignUpProps = Pick<BaseSignUpProps, 'className' | 'afterSignUpUrl' | 'onError' | 'variant' | 'size'> & {
children?: (props: any) => ReactElement;
};
export type SignUpProps = Pick<BaseSignUpProps, 'className' | 'afterSignUpUrl' | 'onError' | 'variant' | 'size'> & {
children?: (props: SignUpRenderProps) => ReactElement;
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nextjs/src/client/components/presentation/SignUp/SignUp.tsx` around
lines 35 - 37, The SignUpProps type currently weakens children to any and the
JSDoc incorrectly documents onSuccess/onComplete; change the children signature
to children?: (props: SignUpRenderProps) => ReactElement (replacing any) in the
SignUpProps declaration, remove the two "as any" casts where children is passed
through (the casts currently masking the type mismatch), and update the
component JSDoc/example to remove onSuccess and onComplete (or alternatively
expose them via BaseSignUpProps if you intend them to be public) so the docs
match the actual public API.


/**
* A styled SignUp component that provides embedded sign-up flow with pre-built styling.
Expand Down Expand Up @@ -69,8 +72,10 @@ const SignUp: FC<SignUpProps> = ({
variant = 'outlined',
afterSignUpUrl,
onError,
children,
...rest
}: SignUpProps) => {
const {signUp} = useAsgardeo();
const {signUp, platform} = useAsgardeo();

/**
* Initialize the sign-up flow.
Expand Down Expand Up @@ -108,6 +113,21 @@ const SignUp: FC<SignUpProps> = ({
return (await signUp(payload)) as unknown as Promise<EmbeddedFlowExecuteResponse>;
};

if (platform === Platform.AsgardeoV2) {
return (
<SignUpV2
className={className}
size={size}
variant={variant}
afterSignUpUrl={afterSignUpUrl}
onError={onError}
{...rest}
>
{children as any}
</SignUpV2>
);
}

return (
<BaseSignUp
afterSignUpUrl={afterSignUpUrl}
Expand All @@ -118,7 +138,10 @@ const SignUp: FC<SignUpProps> = ({
size={size}
variant={variant}
isInitialized={true}
/>
{...rest}
>
{children as any}
</BaseSignUp>
);
};

Expand Down
36 changes: 21 additions & 15 deletions packages/nextjs/src/client/contexts/Asgardeo/AsgardeoProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
} from '@asgardeo/node';
import {
I18nProvider,
FlowMetaProvider,
FlowProvider,
UserProvider,
ThemeProvider,
Expand Down Expand Up @@ -70,6 +71,7 @@ export type AsgardeoClientProviderProps = Partial<Omit<AsgardeoProviderProps, 'b
isSignedIn: boolean;
myOrganizations: Organization[];
organizationHandle: AsgardeoContextProps['organizationHandle'];
platform?: AsgardeoContextProps['platform']
refreshToken: () => Promise<RefreshResult>;
revalidateMyOrganizations?: (sessionId?: string) => Promise<Organization[]>;
signIn: AsgardeoContextProps['signIn'];
Expand Down Expand Up @@ -109,6 +111,7 @@ const AsgardeoClientProvider: FC<PropsWithChildren<AsgardeoClientProviderProps>>
getAllOrganizations,
switchOrganization,
brandingPreference,
platform,
}: PropsWithChildren<AsgardeoClientProviderProps>) => {
const reRenderCheckRef: RefObject<boolean> = useRef(false);
const router: AppRouterInstance = useRouter();
Expand Down Expand Up @@ -301,6 +304,7 @@ const AsgardeoClientProvider: FC<PropsWithChildren<AsgardeoClientProviderProps>>
isLoading,
isSignedIn,
organizationHandle,
platform,
refreshToken,
signIn: handleSignIn,
signInUrl,
Expand All @@ -309,7 +313,7 @@ const AsgardeoClientProvider: FC<PropsWithChildren<AsgardeoClientProviderProps>>
signUpUrl,
user,
}),
[baseUrl, user, isSignedIn, isLoading, signInUrl, signUpUrl, applicationId, organizationHandle],
[baseUrl, user, isSignedIn, isLoading, signInUrl, signUpUrl, applicationId, organizationHandle, platform],
);

const handleProfileUpdate = (payload: User): void => {
Expand All @@ -330,20 +334,22 @@ const AsgardeoClientProvider: FC<PropsWithChildren<AsgardeoClientProviderProps>>
mode={getActiveTheme(preferences?.theme?.mode as any)}
inheritFromBranding
>
<FlowProvider>
<UserProvider profile={userProfile} onUpdateProfile={handleProfileUpdate} updateProfile={updateProfile}>
<OrganizationProvider
createOrganization={createOrganization}
getAllOrganizations={getAllOrganizations}
myOrganizations={myOrganizations}
currentOrganization={currentOrganization}
onOrganizationSwitch={switchOrganization as any}
revalidateMyOrganizations={revalidateMyOrganizations as any}
>
{children}
</OrganizationProvider>
</UserProvider>
</FlowProvider>
<FlowMetaProvider enabled={preferences?.resolveFromMeta !== false}>
<FlowProvider>
<UserProvider profile={userProfile} onUpdateProfile={handleProfileUpdate} updateProfile={updateProfile}>
<OrganizationProvider
createOrganization={createOrganization}
getAllOrganizations={getAllOrganizations}
myOrganizations={myOrganizations}
currentOrganization={currentOrganization}
onOrganizationSwitch={switchOrganization as any}
revalidateMyOrganizations={revalidateMyOrganizations as any}
>
{children}
</OrganizationProvider>
</UserProvider>
</FlowProvider>
</FlowMetaProvider>
</ThemeProvider>
</BrandingProvider>
</I18nProvider>
Expand Down
1 change: 1 addition & 0 deletions packages/nextjs/src/server/AsgardeoProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ const AsgardeoServerProvider: FC<PropsWithChildren<AsgardeoServerProviderProps>>
switchOrganization={switchOrganization}
brandingPreference={brandingPreference}
createOrganization={createOrganization}
platform={config?.platform}
>
{children}
</AsgardeoClientProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,14 @@ const handleOAuthCallbackAction = async (
success: true,
};
} catch (error) {
const message =
error instanceof Error
? error.message
: typeof error === 'object' && error !== null && 'message' in error && typeof (error as any).message === 'string'
? (error as any).message
: 'Authentication failed';
return {
error: error instanceof Error ? error.message : 'Authentication failed',
error: message,
success: false,
};
}
Expand Down
3 changes: 3 additions & 0 deletions packages/nextjs/src/utils/decorateConfigWithNextEnv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* under the License.
*/

import {Platform} from '@asgardeo/node';
import {AsgardeoNextConfig} from '../models/config';

const decorateConfigWithNextEnv = (config: AsgardeoNextConfig): AsgardeoNextConfig => {
Expand All @@ -31,6 +32,7 @@ const decorateConfigWithNextEnv = (config: AsgardeoNextConfig): AsgardeoNextConf
afterSignInUrl,
afterSignOutUrl,
sessionCookieExpiryTime,
platform,
...rest
} = config;

Expand All @@ -43,6 +45,7 @@ const decorateConfigWithNextEnv = (config: AsgardeoNextConfig): AsgardeoNextConf
clientId: clientId || (process.env['NEXT_PUBLIC_ASGARDEO_CLIENT_ID'] as string),
clientSecret: clientSecret || (process.env['ASGARDEO_CLIENT_SECRET'] as string),
organizationHandle: organizationHandle || (process.env['NEXT_PUBLIC_ASGARDEO_ORGANIZATION_HANDLE'] as string),
platform: platform || (process.env['NEXT_PUBLIC_ASGARDEO_PLATFORM'] as keyof typeof Platform | undefined),
scopes: scopes || (process.env['NEXT_PUBLIC_ASGARDEO_SCOPES'] as string),
sessionCookieExpiryTime:
sessionCookieExpiryTime ||
Expand Down
12 changes: 12 additions & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ export type {FlowProviderProps} from './contexts/Flow/FlowProvider';

export {default as useFlow} from './contexts/Flow/useFlow';

export {default as FlowMetaContext} from './contexts/FlowMeta/FlowMetaContext';
export * from './contexts/FlowMeta/FlowMetaContext';

export {default as FlowMetaProvider} from './contexts/FlowMeta/FlowMetaProvider';
export * from './contexts/FlowMeta/FlowMetaProvider';

export {default as useFlowMeta} from './contexts/FlowMeta/useFlowMeta';

export {default as I18nContext} from './contexts/I18n/I18nContext';
export * from './contexts/I18n/I18nContext';

Expand Down Expand Up @@ -112,12 +120,16 @@ export * from './components/control/OrganizationContext/OrganizationContext';
export {default as BaseSignIn} from './components/presentation/auth/SignIn/BaseSignIn';
export * from './components/presentation/auth/SignIn/BaseSignIn';

export {default as SignInV2, type SignInRenderProps} from './components/presentation/auth/SignIn/v2/SignIn';

export {default as SignIn} from './components/presentation/auth/SignIn/SignIn';
export * from './components/presentation/auth/SignIn/SignIn';

export {default as BaseSignUp} from './components/presentation/auth/SignUp/BaseSignUp';
export * from './components/presentation/auth/SignUp/BaseSignUp';

export {default as SignUpV2, type SignUpRenderProps} from './components/presentation/auth/SignUp/v2/SignUp';

export {default as SignUp} from './components/presentation/auth/SignUp/SignUp';
export * from './components/presentation/auth/SignUp/SignUp';

Expand Down
Loading