Installation

Run npm install @rownd/next or yarn add @rownd/next.

Core Components

RowndProvider

The root component that initializes Rownd authentication and state management. Add this to your root layout:

In the root layout.tsx of your app:

import { RowndProvider } from '@rownd/next';

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode,
}>) {
  return (
    <html lang="en">
      <body>
        <RowndProvider
          appKey="<your app key>"
          apiUrl="<your api url>" // Optional for enterprise users
          hubUrlOverride="<your hub url>" // Optional for enterprise users
        >
          {children}
        </RowndProvider>
      </body>
    </html>
  );
}
PropDescriptionRequiredDefault
appKeyYour unique Rownd application identifierYes-
apiUrlEnterprise API endpoint for Rownd servicesNohttps://api.rownd.io
hubUrlOverrideEnterprise URL for the Rownd authentication hub interfaceNohttps://hub.rownd.io

💡 Note
Enterprise endpoints are not needed in most use-cases and these props will default to Rownd’s commercial cloud

Middleware Setup

In your main middleware.ts file, add the Rownd middleware higher-order function. As well as the Rownd token callback path:

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { withRowndMiddleware } from '@rownd/next/server';

export const middleware = withRowndMiddleware((request: NextRequest) => {
  return NextResponse.next();
});

export const config = {
  matcher: [
    // Required for Rownd token handling
    '/api/rownd-token-callback',
    // Add your protected routes
    '/protected/:path*'
  ]
};

Authentication Components

Protected Routes / Pages

To protect a page from being accessed by unauthenticated users, you can use the withRowndRequireSignIn higher-order component.

import {
  withRowndRequireSignIn,
  getRowndUser,
  getAccessToken,
  isAuthenticated,
} from '@rownd/next/server';
import { cookies } from 'next/headers';

async function ProtectedPage() {
  const user = await getRowndUser(cookies);
  const isAuthenticated = await isAuthenticated(cookies);
  const accessToken = await getAccessToken(cookies);
  
  return (
    <div>
      <h1>Welcome {user.data?.user_id}</h1>
      <p>Your access token: {user.access_token}</p>
    </div>
  );
}

// Fallback component shown during authentication
function AuthFallback() {
  return <div>Please sign in to continue...</div>;
}

export default withRowndRequireSignIn(ProtectedPage, cookies, AuthFallback, {
  onUnauthenticated: () => {
    // Optional callback when user is not authenticated
  }
});

Client-Side Authentication

Use the useRownd hook to access authentication state and methods:

'use client';

import { useRownd } from '@rownd/next';

export function ClientPage() {
  const { 
    is_authenticated,
    is_initializing,
    access_token,
    requestSignIn,
    signOut
  } = useRownd();

  if (is_initializing) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      {is_authenticated ? (
        <button onClick={() => signOut()}>Sign Out</button>
      ) : (
        <button onClick={() => requestSignIn()}>Sign In</button>
      )}
    </div>
  );
}

Server Utilities

getRowndUser

Server-side function to get the current authenticated user:

import { getRowndUser } from '@rownd/next/server';
import { cookies } from 'next/headers';

async function ServerComponent() {
  const user = await getRowndUser(cookies);
  
  if (!user) {
    return <div>Not authenticated</div>;
  }
  
  return (
    <div>
      <h1>User ID: {user.data?.user_id}</h1>
      <h1>Email: {user.data?.email}</h1>
      <h1>First name: {user.data?.first_name}</h1>
      <h1>Last name: {user.data?.last_name}</h1>
    </div>
  );
}

State Management

The SDK uses a custom store implementation for managing authentication state. The store includes:

interface RowndState {
  is_initializing: boolean;
  is_authenticated: boolean;
  access_token: string | null;
  user: {
    data: Record<string, any>;
    groups: string[];
    redacted_fields: string[];
    verified_data: Record<string, any>;
    meta: Record<string, any>;
    is_loading: boolean;
  };
}

Available Methods

The useRownd hook provides the following methods:

MethodDescriptionReturn Type
requestSignIn()Triggers the sign-in modalvoid
signOut()Signs out the current uservoid
setUser()Updates user dataPromise<UserContext>
getAccessToken()Gets the current access tokenPromise<string>
manageAccount()Opens the account management interfacevoid
getFirebaseIdToken()Gets the Firebase ID tokenPromise<string>
setUserValue()Updates specific user fieldPromise<UserContext>

API reference

Please see the React SDK for details on Rownd Client React API’s.

Note: These are for CLIENT SIDE ONLY:

Most API methods are made available via the Rownd Provider and its associated useRownd React hook. Unless otherwise noted, we’re assuming that you’re using hooks.

requestSignIn()

Trigger the Rownd sign in dialog

const { requestSignIn } = useRownd();

requestSignIn({
  auto_sign_in: false, // optional
  identifier: "me@company.com" || "+19105551212", // optional
});
  • auto_sign_in: boolean - when true, automatically trigger a sign-in attempt if identifier is included or an email address or phone number has already been set in the user data.

  • identifier: string - an email address or phone number (in E164 format) to which a verification message may be sent. If the Rownd app is configured to allow unverified users, then sign-in will complete without verification if the user has not signed in previously.

signOut()

Sign out the user and clear their profile, returning them to a completely unauthenticated state.

const { signOut } = useRownd();
signOut();

getAccessToken()

Retrieves the active, valid access token for the current user.

const { getAccessToken } = useRownd();

let accessToken = await getAccessToken({
  waitForToken: false,
});
  • waitForToken: boolean - when true, if no access token is present or if it’s expired, the promise will not resolve until a valid token is available. While unlikely, this could result in waiting forever.

is_initializing

is_initializing will be true until the Hub has fully loaded, recalled its state, and resolved the current user’s authentication status. This usually takes only a few milliseconds, but if you make decisions that depend on the is_authenticated flag while is_initializing is still true, your code/logic may not work as you expect.

const { is_initializing } = useRownd();

if (is_initializing) {
  // return loading state or null
}

is_authenticated

const { is_authenticated } = useRownd();

return (
  <>
    {is_authenticated && <ProtectedRoute />}
    {!is_authenticated && <PublicRoute />}
  </>
);

access_token

Represents the current access token for the user.

const { access_token } = useRownd();

useEffect(() => {
    axios({
        method: 'post',
        url: '/api/sessions'
        headers: {
            authorization: `Bearer ${access_token}`
        }
    }).then(console.log);
}, [access_token]);

user

Represents information about the current user, specifically their profile information. In the example below, we use the existing data to display the current value of first_name in a form field, update a local copy of that data as the user changes it, and then save the changes to Rownd once the user submits the form.

const { user, setUser } = useRownd();

const [profile, setProfile] = useState(user.data);

return (
  <form onSubmit={() => setUser(profile)}>
    <label htmlFor="first_name">
      <input
        id="first_name"
        type="text"
        value={profile?.first_name}
        onInput={(evt) => setProfile({ ...profile, first_name: evt.target.value })}
      />
    </label>
    <button type="submit">Save</button>
  </form>
);

setUser

The setUser function allows you to update a user’s profile information within the Rownd platform. You can modify user attributes such as first_name, last_name, and other properties by passing an object with the relevant fields.

const { setUser } = useRownd();

setUser({
  first_name: "Alice",
  last_name: "Ranier",
});

setUserValue

The setUserValue function allows you to update a specific attribute of the user’s profile within the Rownd platform. Instead of passing an entire user object, you can update individual fields by specifying the key (attribute name) and value.

const { setUserValue } = useRownd();

setUserValue("first_name", "Alice");

manageAccount()

The manageAccount() function allows users to view and update their profile information within the Rownd platform. This function opens the user’s account management interface, where they can review and modify personal details such as their name, email, and other profile attributes.

const { manageAccount } = useRownd();

<Button onClick={() => manageAccount()}>Manage Account</Button>;

passkeys

Rownd offers passkey-based authentication, allowing users to create and authenticate using a secure passkey. The register function starts the process of creating a new passkey for the user, while the authenticate function validates an existing passkey to authenticate the user.

const { passkeys } = useRownd();

<div>
  <Button onClick={() => passkeys.register()}>Register Passkey</Button>
  <Button onClick={() => passkeys.authenticate()}>Authenticate with Passkey</Button>
</div>;

RequireSignIn

The RequireSignIn component is a wrapper that triggers the sign-in process when the component it wraps is rendered. It ensures that the user is signed in before accessing the content of the wrapped component. If the user is not authenticated, the sign-in process will automatically begin when the component mounts.

const App = () => {
  return (
    <RequireSignIn>
      <h1>Home page<h1/>
    </RequireSignIn>
  );
};

SignedIn

The SignedIn component is used to conditionally render its children only when the user is authenticated. If the user is not signed in, the wrapped content will not be displayed.

const App = () => {
  return (
    <SignedIn>
      <ProtectedContent />
    </SignedIn>
  );
};

SignedOut

The SignedOut component is the counterpart to SignedIn. It renders its children only when the user is not authenticated. If the user is signed in, the wrapped content will not be displayed.

const App = () => {
  return (
    <SignedOut>
      <LoginPrompt />
    </SignedOut>
  );
};