@passflow/passflow-react-sdk
TypeScript icon, indicating that this package has built-in type declarations

0.1.37 • Public • Published

@passflow/passflow-react-sdk

This is a SDK for react application.

Table of Contents

to install just type:

pnpm install
pnpm build

Local Development

Using Local Passflow JS SDK

For local development and testing with a local version of the Passflow JS SDK, you need to:

  1. Clone the Passflow JS SDK repository in a sibling directory to this project.
  2. remove current dependecy pnpm remove @passflow/passflow-js-sdk
  3. Link folder with:
pnpm link ../passflow-js-sdk
pnpm install

Now you can run watch mode in libraray mode and change it. It will compile every changes incrementally.

pnpm watch

After all done, we need to unlink and return all to the original state

pnpm remove @passflow/passflow-js-sdk
pnpm unlink @passflow/passflow-js-sdk
pnpm install @passflow/passflow-js-sdk

Test writing Environment Setup

For local development and UI testing, you need to set up the Passflow environment:

  1. Set the PASSFLOW_URL environment variable to point to your Passflow instance.
  2. Set the PASSFLOW_APP_ID environment variable
  3. Run pnpm dev anmd all should works

Refer .env.example for more details.

we are using pnpm. Please ansure you have it in the system.

UI Testing

We are using playwright to run UI tests.

First, ensure you have all runtime binary enabled:

pnpm exec playwright install

and then feel free to run the tests:

pnpm run test:ui

Writing your own ui tests.

You can find a tests in the ./tests frolder.

Please create the new files using the current tests as a reference.

To run the playwright in the design mode with ui, run the follwoing command:

pnpm playwright test --ui

Installation

pnpm add @passflow/passflow-react-sdk

Requirements

  • React 18+
  • React Router DOM v6/v7 or Wouter or TanStack Router

Integration

Passflow Cloud

For a quick start with Passflow Cloud:

const passflowConfig: PassflowConfig = {
  url: process.env.PASSFLOW_URL ?? 'http://localhost:5432',
  appId: process.env.PASSFLOW_APP_ID ?? 'test_app_id',
  createTenantForNewUser: true,
  scopes: ['openid', 'email', 'profile', 'offline'],
};

export const PassflowProviderWrapper: FC<PropsWithChildren> = ({
  children,
}) => {
  const navigate = useNavigate(); // from react-router-dom

  return (
    <PassflowProvider
      url={passflowConfig.url}
      appId={passflowConfig.appId}
      createTenantForNewUser={passflowConfig.createTenantForNewUser}
      scopes={passflowConfig.scopes}
      navigate={(options) =>
        navigate(
          {
            pathname: options.to,
            search: options.search,
          },
          { replace: options.replace }
        )
      }
      router="react-router"
    >
      {children}
    </PassflowProvider>
  );
};

export const App = () => (
  <BrowserRouter>
    <PassflowProviderWrapper>
      <PassflowFlow
        federatedDisplayMode='redirect'
        successAuthRedirect='https://jwt.io'
        federatedCallbackUrl='https://jwt.io'
        pathPrefix='/web'
      />
    </PassflowProviderWrapper>
  </BrowserRouter>
);

PassflowFlow

Prop Type Description
successAuthRedirect string URL to redirect after successful authentication
federatedCallbackUrl string URL to redirect after successful federated authentication
federatedDisplayMode "popup" | "redirect" Federated authentication display mode
pathPrefix string Prefix for all routes (optional)

React Router DOM

Example of integration with React Router DOM: PS: The example uses the Declarative approach.

import {
  PassflowProvider,
  SignIn,
  SignUp,
  ForgotPassword,
  ForgotPasswordSuccess,
} from "@passflow/passflow-react-sdk";
import { BrowserRouter, Routes, Route, useNavigate } from "react-router-dom";

const passflowConfig = {
  url: import.meta.env.VITE_PASSFLOW_URL,
  appId: import.meta.env.VITE_PASSFLOW_APP_ID,
  createTenantForNewUser: true,
  scopes: ["id", "offline", "email", "profile", "openid", "management"],
};

const PassflowProviderWrapper = ({ children }) => {
  const navigate = useNavigate();

  return (
    <PassflowProvider
      url={passflowConfig.url}
      appId={passflowConfig.appId}
      createTenantForNewUser={passflowConfig.createTenantForNewUser}
      scopes={passflowConfig.scopes}
      navigate={(options) =>
        navigate(
          {
            pathname: options.to,
            search: options.search,
          },
          { replace: options.replace }
        )
      }
      router="react-router"
    >
      {children}
    </PassflowProvider>
  );
};

export const App = () => (
  <BrowserRouter>
    <PassflowProviderWrapper>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/signin" element={<SignIn successAuthRedirect="/" signUpPath="/signup" />} />
        <Route path="/signup" element={<SignUp successAuthRedirect="/" signInPath="/signin" />} />
        <Route 
          path="/forgot-password" 
          element={
            <ForgotPassword
              successResetRedirect="/"
              signInPath="/signin"
              forgotPasswordSuccessPath="/forgot-password/success"
            />
          } 
        />
        <Route path="/forgot-password/success" element={<ForgotPasswordSuccess />} />
        {/* Add other routes here */}
      </Routes>
    </PassflowProviderWrapper>
  </BrowserRouter>
);

Wouter

Example of integration with Wouter:

import {
  PassflowProvider,
  SignIn,
  SignUp,
  ForgotPassword,
  ForgotPasswordSuccess,
} from "@passflow/passflow-react-sdk";
import { Switch, Route, useLocation } from "wouter";

const passflowConfig = {
  url: import.meta.env.VITE_PASSFLOW_URL,
  appId: import.meta.env.VITE_PASSFLOW_APP_ID,
  createTenantForNewUser: true,
  scopes: ["id", "offline", "email", "profile", "openid", "management"],
};

const PassflowProviderWrapper = ({ children }) => {
  const [, navigate] = useLocation();

  return (
    <PassflowProvider
      url={passflowConfig.url}
      appId={passflowConfig.appId}
      createTenantForNewUser={passflowConfig.createTenantForNewUser}
      scopes={passflowConfig.scopes}
      navigate={(options) => {
        const searchParamWouter = options.search
          ? options.search.startsWith("?")
            ? options.search
            : `?${options.search}`
          : "";
        navigate(`${options.to}${searchParamWouter}`, {
          replace: options.replace,
        });
      }}
      router="wouter"
    >
      {children}
    </PassflowProvider>
  );
};

export const App = () => (
  <Switch>
    <PassflowProviderWrapper>
      <Route path="/" component={Home} />
      <Route path="/signin" component={SignInWrapper} />
      <Route path="/signup" component={SignUpWrapper} />
      <Route path="/forgot-password" component={ForgotPasswordWrapper} />
      <Route path="/forgot-password/success" component={ForgotPasswordSuccessWrapper} />
      {/* Add other routes here */}
    </PassflowProviderWrapper>
  </Switch>
);

TanStack Router

Example of integration with TanStack Router: PS: The example uses Code-Based Routing.

// App.tsx
import { PassflowProviderWrapper, RouterProvider } from './providers';

export const App = () => (
  <PassflowProviderWrapper>
    <RouterProvider />
  </PassflowProviderWrapper>
);

// PassflowProviderWrapper.tsx
import { PassflowProvider } from '@passflow/passflow-react-sdk';

const passflowConfig = {
  url: import.meta.env.VITE_PASSFLOW_URL,
  appId: import.meta.env.VITE_PASSFLOW_APP_ID,
  createTenantForNewUser: true,
  scopes: ['id', 'offline', 'email', 'profile', 'openid', 'management'],
};

export const PassflowProviderWrapper = ({ children }) => (
  <PassflowProvider
    url={passflowConfig.url}
    appId={passflowConfig.appId}
    createTenantForNewUser={passflowConfig.createTenantForNewUser}
    scopes={passflowConfig.scopes}
    router="tanstack-router"
  >
    {children}
  </PassflowProvider>
);

// router/root.tsx
import { useNavigation } from '@passflow/passflow-react-sdk';
import { Outlet, useNavigate } from '@tanstack/react-router';

export const Root = () => {
  const navigate = useNavigate();
  const { setNavigate } = useNavigation();

  useEffect(() => {
    setNavigate((options) => navigate(options));
  }, [navigate, setNavigate]);

  return <Outlet />;
};

// router.tsx
import { QueryClient } from '@tanstack/react-query';
import { createRouter } from '@tanstack/react-router';
import { queryClient } from '../query';
import { routerTree } from './routes';
import { Passflow } from '@passflow/passflow-react-sdk';

export interface RouterContext {
  queryClient: QueryClient;
  passflow?: Passflow;
}

export const router = createRouter({
  routeTree: routerTree,
  context: {
    queryClient,
    passflow: undefined,
  },
  defaultPreload: 'intent',
});

declare module '@tanstack/react-router' {
  interface Register {
    router: typeof router;
  }
}


// routes.tsx
import { Outlet, createRootRouteWithContext, createRoute, redirect } from '@tanstack/react-router';
import { RouterContext } from './router';
import { Root } from './root';
import { About, Home } from '@/pages';
import { ForgotPassword, ForgotPasswordSuccess, SignIn, SignUp } from '@passflow/passflow-react-sdk';
import { RootLayout } from '@/layouts';

const redirectToSignin = () => {
  throw redirect({
    to: '/signin',
  });
};

const rootRoute = createRootRouteWithContext<RouterContext>()({
  component: Root,
  notFoundComponent: () => <div>404 Not Found</div>,
});

// PUBLIC ROUTES
const publicRoute = createRoute({
  getParentRoute: () => rootRoute,
  id: 'public',
  component: () => <Outlet />,
});

const signInRoute = createRoute({
  getParentRoute: () => publicRoute,
  path: '/signin',
  component: () => <SignIn successAuthRedirect='/' signUpPath='/signup' />,
});

const signUpRoute = createRoute({
  getParentRoute: () => publicRoute,
  path: '/signup',
  component: () => <SignUp successAuthRedirect='/' signInPath='/signin' />,
});

const forgotPasswordRoute = createRoute({
  getParentRoute: () => publicRoute,
  path: '/forgot-password',
  component: () => (
    <ForgotPassword successResetRedirect='/' signInPath='/signin' forgotPasswordSuccessPath='/forgot-password/success' />
  ),
});

const forgotPasswordSuccessRoute = createRoute({
  getParentRoute: () => publicRoute,
  path: '/forgot-password/success',
  component: () => <ForgotPasswordSuccess />,
});

{/* Add other PASSFLOW COMPONENTS routes here */}

// PROTECTED ROUTES
const protectedRoute = createRoute({
  getParentRoute: () => rootRoute,
  id: 'protected',
  beforeLoad: async ({ context }) => {
    const { passflow } = context;

    await passflow?.session({
      createSession: async (tokens) => {
        console.log(tokens); // if session is created, this function will be called with the tokens
      },
      expiredSession: async () => {
        console.log('expiredSession');
        redirectToSignin(); // if session is expired and refresh token is not valid, redirect to signin
      },
      doRefresh: true,
    });
  },
  component: () => <RootLayout />,
});

const dashboardRoute = createRoute({
  getParentRoute: () => protectedRoute,
  path: '/',
  component: () => <Home />,
});

const aboutRoute = createRoute({
  getParentRoute: () => protectedRoute,
  path: '/about',
  component: () => <About />,
});

{/* Add other protected routes here */}

export const routerTree = rootRoute.addChildren([
  publicRoute.addChildren([signInRoute, signUpRoute, forgotPasswordRoute, forgotPasswordSuccessRoute]),
  protectedRoute.addChildren([dashboardRoute, aboutRoute]),
]);

Props

PassflowProvider

Prop Type Description
url string Passflow server URL
appId string Application ID
createTenantForNewUser boolean Whether to create a tenant for new users
scopes string[] Array of required scopes
router "default" | "react-router" | "wouter" | "tanstack-router" Router being used (optional) (default is native window navigation)
navigate (options: NavigateOptions) => void Navigation function (optional) (default is native window navigation)

Form Components

SignIn

Component for user authentication.

Prop Type Description Default
successAuthRedirect string URL to redirect after successful sign in Required
signUpPath string Path to sign up page (optional) /signup
forgotPasswordPath string Path to forgot password page (optional) /forgot-password
verifyMagicLinkPath string Path to verify magic link page (optional) /verify-challenge-magic-link
verifyOTPPath string Path to verify OTP page (optional) /verify-challenge-otp
federatedCallbackUrl string URL for federated authentication callback (optional) window.location.origin
federatedDisplayMode "popup" | "redirect" Display mode for federated authentication (optional) "popup"

SignUp

Component for user registration.

Prop Type Description Default
successAuthRedirect string URL to redirect after successful sign up Required
signInPath string Path to sign in page (optional) /signin
verifyMagicLinkPath string Path to verify magic link page (optional) /verify-challenge-magic-link
verifyOTPPath string Path to verify OTP page (optional) /verify-challenge-otp
federatedCallbackUrl string URL for federated authentication callback (optional) window.location.origin
federatedDisplayMode "popup" | "redirect" Display mode for federated authentication (optional) "popup"

ForgotPassword

Component for password recovery initiation.

Prop Type Description Default
successResetRedirect string URL to redirect after successful password reset Required
signInPath string Path to sign in page (optional) /signin
forgotPasswordSuccessPath string Path to success page after initiating password reset (optional) /forgot-password/success

ForgotPasswordSuccess

Component for password recovery success.

No props required.

ResetPassword

Component for setting a new password.

Prop Type Description Default
successAuthRedirect string URL to redirect after successful password reset Required

VerifyChallengeMagicLink

Component for verifying magic link authentication.

No props required.

VerifyChallengeOTP

Component for OTP verification.

Prop Type Description Default
successAuthRedirect string URL to redirect after successful verification Required
numInputs number Number of OTP input fields (optional) 6
shouldAutoFocus boolean Whether to autofocus the first input (optional) true
signUpPath string Path to sign up page (optional) /signup

InvitationJoin

Component for accepting invitations and joining organizations.

Prop Type Description Default
successAuthRedirect string URL to redirect after successful join Required
signInPath string Path to sign in page (optional) /signin

Hooks

useAuth

Hook for authentication management. Provides methods for checking authentication status, obtaining tokens, and logging out.

const { isAuthenticated, getTokens, logout, isLoading } = useAuth();
Parameter Type Description
initialRefresh boolean (optional) Whether to refresh tokens on mount

Returns:

Property Type Description
isAuthenticated () => boolean Current authentication status
getTokens (doRefresh: boolean) => Promise<{ tokens: Tokens | undefined; parsedTokens: ParsedTokens | undefined; }> Function to get authentication tokens
logout () => void Function to log out user
isLoading boolean Loading state indicator

usePassflow

Hook for accessing the Passflow SDK instance. Must be used within PassflowProvider.

const passflow = usePassflow();

Returns:

Type Description
Passflow Passflow SDK instance

usePassflowStore

Hook for synchronizing state with Passflow SDK. Allows subscribing to token changes.

const tokens = usePassflowStore([PassflowEvent.SignIn, ...]);
Parameter Type Description
events PassflowEvent[] (optional) Events to subscribe to

Returns:

Type Description
Tokens | undefined Current tokens state

useSignIn

Hook for implementing sign-in functionality. Supports password, passkey, and passwordless authentication.

const { fetch, isLoading, isError, error } = useSignIn();

Returns:

Property Type Description
fetch (payload: PassflowPasskeyAuthenticateStartPayload | PassflowSignInPayload | PassflowPasswordlessSignInPayload, type: 'passkey' | 'password' | 'passwordless') => Promise<boolean | string | PassflowPasswordlessResponse> Sign in function
isLoading boolean Loading state
isError boolean Error state
error string Error message

useSignUp

Hook for implementing registration functionality. Supports password, passkey, and passwordless registration.

const { fetch, isLoading, isError, error } = useSignUp();

Returns:

Property Type Description
fetch (payload: PassflowPasskeyRegisterStartPayload | PassflowSignUpPayload | PassflowPasswordlessSignInPayload, type: 'passkey' | 'password' | 'passwordless') => Promise<boolean | PassflowPasswordlessResponse> Sign up function
isLoading boolean Loading state
isError boolean Error state
error string Error message

useNavigation

Hook for navigation between pages. Supports various routers (react-router, wouter, tanstack-router).

const { navigate, setNavigate } = useNavigation();

Returns:

Property Type Description
navigate NavigateFunction Navigation function
setNavigate (newNavigate: NavigateFunction | null) => void Function to update navigation handler

useProvider

Hook for working with federated authentication providers (OAuth).

const { federatedWithPopup, federatedWithRedirect } = useProvider(redirectUrl);
Parameter Type Description
redirectUrl string URL to redirect after authentication

Returns:

Property Type Description
federatedWithPopup (provider: Providers) => void Popup authentication function
federatedWithRedirect (provider: Providers) => void Redirect authentication function

useResetPassword

Hook for resetting user password.

const { fetch, isLoading, isError, error } = useResetPassword();

Returns:

Property Type Description
fetch (newPassword: string) => Promise<boolean> Password reset function
isLoading boolean Loading state
isError boolean Error state
error string Error message

useUserPasskeys

Hook for managing user passkeys (create, edit, delete).

const { data, createUserPasskey, editUserPasskey, deleteUserPasskey } = useUserPasskeys();

Returns:

Property Type Description
data PassflowUserPasskey[] List of user passkeys
createUserPasskey (relyingPartyId: string) => Promise<void> Create passkey function
editUserPasskey (newName: string, passkeyId: string) => Promise<void> Edit passkey function
deleteUserPasskey (passkeyId: string) => Promise<void> Delete passkey function
isLoading boolean Loading state
isError boolean Error state
errorMessage string Error message

useAppSettings

Hook for retrieving application settings and password policies.

const { appSettings, passwordPolicy, passkeyProvider } = useAppSettings();

Returns:

Property Type Description
appSettings AppSettings | null Application settings
passwordPolicy PassflowPasswordPolicySettings | null Password policy settings
passkeyProvider PassflowPasskeySettings | null Passkey provider settings
isLoading boolean Loading state
isError boolean Error state
error string Error message

useAuthCloudRedirect

Hook for redirecting to Passflow Cloud.

const redirect = useAuthCloudRedirect(cloudPassflowUrl);
Parameter Type Description
cloudPassflowUrl string Passflow Cloud URL

Returns:

Type Description
() => void Redirect function

useForgotPassword

Hook for initiating the password recovery process.

const { fetch, isLoading, isError, error } = useForgotPassword();

Returns:

Property Type Description
fetch (payload: PassflowSendPasswordResetEmailPayload) => Promise<boolean> Password recovery function
isLoading boolean Loading state
isError boolean Error state
error string Error message

useJoinInvite

Hook for accepting organization invitations.

const { fetch, isLoading, isError, error } = useJoinInvite();

Returns:

Property Type Description
fetch (token: string) => Promise<boolean> Join invitation function
isLoading boolean Loading state
isError boolean Error state
error string Error message

useLogout

Hook for logging out of the system.

const { fetch, isLoading, isError, error } = useLogout();

Returns:

Property Type Description
fetch () => Promise<boolean> Logout function
isLoading boolean Loading state
isError boolean Error state
error string Error message

usePasswordlessComplete

Hook for completing passwordless authentication.

const { fetch, isLoading, isError, error } = usePasswordlessComplete();

Returns:

Property Type Description
fetch (payload: PassflowPasswordlessSignInCompletePayload) => Promise<PassflowValidationResponse | null> Complete passwordless auth function
isLoading boolean Loading state
isError boolean Error state
error string Error message

Package Sidebar

Install

npm i @passflow/passflow-react-sdk

Weekly Downloads

86

Version

0.1.37

License

MIT

Unpacked Size

1.95 MB

Total Files

182

Last publish

Collaborators

  • ivan_holiak
  • jackrudenko