Follow this quick start tutorial to get up and running with your first Headless project.
This tutorial walks you through the project setup process and builds a simple site that uses tokens to maintain persistent visitor sessions and to authenticate site members.
You can use the code described here as a springboard for your own project. After building the foundation here to handle visitors and members, you can continue your development by making use of the various modules in the Wix Javascript SDK.
For detailed instructions for managing visitors and members, see Handle Visitors, Handle Members with Managed Login, and Handle Members with Custom Login.
This tutorial shows you how to implement:
- A React component that handles login and logout by redirecting the visitor to a Wix-managed page.
- A callback page that verifies login and saves member tokens in a cookie.
- Next.js middleware that checks for an existing member or visitor token and generates a new visitor token if one is not found.
The tutorial is based on the Wix Headless example site. You can test out the live example site, or fork the site's code repo to use as a starting point for your own site or app.
This implementation focuses on simplicity and understandability, rather than feature richness, performance or completeness. For details about additional functionality, see the API Reference. Looking for a more comprehensive example site integrating Wix Headless APIs? Check out our starter templates.
Note: The code in this tutorial is written in JSX, but you can use the SDK in any JavaScript environment.
Implementing the session management flow includes the following steps:
- Set up the Wix Headless environment.
- Create a login component.
- Create a callback page.
- Create middleware for managing tokens.
Before using the SDK, there are a few things you need to set up on your Wix account and in your external site or app's coding environment.
To set up the Wix Headless environment, follow these steps:
- If you haven't already, create a project.
When prompted to add functionalities to your new project, select whichever business solutions your project needs. - Set up authorization for your site by creating and configuring an OAuth app.
- Install the SDK client and relevant SDK module packages by running the following commands:
For NPM:
For Yarn:Copy Codenpm install @wix/sdknpm install @wix/membersCopy Codeyarn add @wix/sdkyarn add @wix/members - Install the
react
package to handle UI rendering, thejs-cookie
package to handle session cookies, and thenext/server
package with helper functions for Next.js middleware.
For NPM:
For Yarn:Copy Codenpm install reactnpm install js-cookienpm install next/serverCopy Codeyarn add reactyarn add js-cookieyarn add next/server
Follow these steps to create a React component that handles login and logout by redirecting the visitor to a Wix-managed page.
To set up the code file for the login component, follow these steps:
-
Add the following import statements to the top of your code file:
Copy Codeimport { createClient, OAuthStrategy } from '@wix/sdk';import { members } from '@wix/members';import { useEffect, useState } from 'react';import Cookies from 'js-cookie'; -
Create an SDK client by adding the following code to your code file. Replace the value for
clientId
with your OAuth app's client ID. You can find the ID in your project's Headless Settings menu.The value for
tokens
is the'session'
cookie on the visitor's browser. It's used to make calls to the Wix API. This way, you can maintain previous visitor sessions. If a token has already been generated for the visitor, this token is used.Copy Codeconst myWixClient = createClient({modules: { members },auth: OAuthStrategy({clientId: `<YOUR-CLIENT-ID>`,tokens: JSON.parse(Cookies.get('session') || null),}),});
The logic for our example login request flow is contained in a React component called LoginBar
. To create the component, follow these steps:
-
Define the component function as a default export in your code file:
Copy Codeexport default function LoginBar() {} -
Define a state variable by adding the following code in the component function:
Copy Codeconst [member, setMember] = useState([]);In the steps that follow, the
member
state variable stores a visitor's data if they are a logged-in site member.
Add the following 3 functions for handling member sessions to the LoginBar
component:
-
fetchMember()
- Uses the SDK client'sauth.loggedIn()
function to check if the current site visitor is a logged-in site member. If they are, the rendered UI is updated with the member's details. This function runs when the component is mounted.Copy Codeasync function fetchMember() {const { member } = myWixClient.auth.loggedIn()? await myWixClient.members.getMyMember(): {};setMember(member || undefined);} -
login()
- Uses the SDK client'sauth.generateOAuthData()
andauth.getAuthUrl()
functions to log in a site visitor. This function runs when a Login button in the rendered UI is clicked.Copy Codeasync function login() {const data = myWixClient.auth.generateOAuthData(`${window.location.origin}/login-callback`,window.location.href);localStorage.setItem('oauthRedirectData', JSON.stringify(data));const { authUrl } = await myWixClient.auth.getAuthUrl(data);window.location = authUrl;}The SDK client's
auth.generateOAuthData()
function generates the data needed for authorization, which is saved in local storage with the keyoauthRedirectData
. When the Wix-managed authentication process is over, Wix redirects the visitor to the URL provided inredirectUri
. Theauth.getAuthUrl()
function returns a URL for a Wix-managed authentication page calledauthUrl
. -
logout()
- Uses the SDK client'sauth.logout()
function to log out a site member and remove the session cookie from their browser. This function runs when a Logout button in the rendered UI is clicked.Copy Codeasync function logout() {const { logoutUrl } = await myWixClient.auth.logout(window.location.href);Cookies.remove('session');window.location = logoutUrl;}
Add the following code to the LoginBar
component to run the fetchMember()
function after the component is rendered. This ensures that member data is retrieved when the component mounts.
Copy Code
useEffect(() => {fetchMember();}, []);
Add the following code to the LoginBar
component function's return
statement to render the UI.
Copy Code
return (<div>{member !== null && (<sectiononClick={() => (myWixClient.auth.loggedIn() ? logout() : login())}><h3>Hello{' '}{myWixClient.auth.loggedIn()? member.profile?.nickname || member.profile?.slug || '': 'visitor'},</h3><span>{myWixClient.auth.loggedIn() ? 'Logout' : 'Login'}</span></section>)}</div>);
The UI displays the following:
- If no member is logged in: Hello visitor and a Login link.
- If a member is logged in: Hello, <USER_NAME> and a Logout link.
Follow these steps to create a callback page for Wix to redirect the visitor to after handling authentication.
To set up the code file for the callback page, follow these steps:
-
Add the following import statements to the top of your code file:
Copy Codeimport Cookies from 'js-cookie';import { useEffect, useState } from 'react';import { createClient, OAuthStrategy } from '@wix/sdk'; -
Create an SDK client by adding the following code to your code file:
Copy Codeconst myWixClient = createClient({auth: OAuthStrategy({clientId: `<YOUR-CLIENT-ID>`,tokens: JSON.parse(Cookies.get('session') || null),}),});
The logic for our example login request flow is contained in a React component called LoginCallback
. To create the component, follow these steps:
-
Define the component function as a default export in your code file:
Copy Codeexport default function LoginCallback() {} -
Define state variables by adding the following code in the component function:
Copy Codeconst [nextPage, setNextPage] = useState(null);const [errorMessage, setErrorMessage] = useState(null);In the steps that follow, the
nextPage
state variable stores the URL of the page to redirect the visitor to, and theerrorMessage
state variable stores the error received if there is an error generating a member token.
Add the following function to the LoginCallback
component. This function first retrieves the authorization data saved in local storage by the Login
component. Then it retrieves the authorization code and state from the callback page's URL using auth.parseFromUrl()
. Using this data, it calls auth.getMemberTokens()
to generate access and refresh tokens, which it stores in the 'session'
cookie. It then redirects the visitor to the page specified in data.originalUri
if it exists, or otherwise to /
.
Copy Code
async function verifyLogin() {const data = JSON.parse(localStorage.getItem('oauthRedirectData'));localStorage.removeItem('oauthRedirectData');try {const { code, state } = myWixClient.auth.parseFromUrl();let tokens = await myWixClient.auth.getMemberTokens(code, state, data);while (!tokens?.refreshToken?.value) {tokens = await myWixClient.auth.getMemberTokens(code, state, data);}Cookies.set('session', JSON.stringify(tokens));window.location = data?.originalUri || '/';} catch (e) {setNextPage(data?.originalUri || '/');setErrorMessage(e.toString());}}
Add the following code to the LoginCallback
component to run the verifyLogin()
function after the component is rendered. This ensures that tokens are stored when the component mounts.
Copy Code
useEffect(() => {verifyLogin();}, []);
Add the following code to the LoginCallback
component function's return
statement to render the UI.
Copy Code
return (<article>{errorMessage && (<><span>{errorMessage}</span><br /><br /></>)}{nextPage ? <a href={nextPage}>Continue</a> : <>Loading...</>}</article>);
The UI displays the following before redirecting the visitor:
- If there was an error,
errorMessage
is displayed. - If login was verified, a link to the next page with the text Continue is rendered, along with the text Loading....
Once you've implemented a login component and a callback page, follow these steps to create Next.js middleware to check a visitor's session status when loading every page.
To set up the code file for the session management middleware, follow these steps:
-
Add the following import statements to the top of your code file:
Copy Codeimport { createClient, OAuthStrategy } from '@wix/sdk';import { NextResponse } from '/next/server';
The logic for our middleware is contained in a function called middleware()
. This function checks if a 'session'
cookie already exists in the page request. If the cookie isn't found, it generates new visitor tokens using auth.generateVisitorTokens()
and stores them in a 'session'
cookie to create a new anonymous session which persists when the visitor uses the site from the same browser.
Implement this function as follows:
Copy Code
export async function middleware(request) {if (!request.cookies.get('session')) {const response = NextResponse.next();const myWixClient = createClient({auth: OAuthStrategy({ clientId: `<YOUR-CLIENT-ID>` }),});response.cookies.set('session',JSON.stringify(await myWixClient.auth.generateVisitorTokens()));return response;}}
You can use the following full code examples as a starting point for developing your own site:
Copy Code
import Cookies from 'js-cookie';import { useEffect, useState } from 'react';import { createClient, OAuthStrategy } from '@wix/sdk';import { members } from '@wix/members';const myWixClient = createClient({modules: { members },auth: OAuthStrategy({clientId: `10c1663b-2cdf-47c5-a3ef-30c2e8543849`,tokens: JSON.parse(Cookies.get('session') || null),}),});export default function LoginBar() {const [member, setMember] = useState(null);async function fetchMember() {const { member } = myWixClient.auth.loggedIn()? await myWixClient.members.getMyMember(): {};setMember(member || undefined);}async function login() {const data = myWixClient.auth.generateOAuthData(`${window.location.origin}/login-callback`,window.location.href);localStorage.setItem('oauthRedirectData', JSON.stringify(data));const { authUrl } = await myWixClient.auth.getAuthUrl(data);window.location = authUrl; // wix auth will send the user back to the callback page (login-callback.js)}async function logout() {const { logoutUrl } = await myWixClient.auth.logout(window.location.href);Cookies.remove('session');window.location = logoutUrl;}useEffect(() => {fetchMember();}, []);return (<div>{member !== null && (<sectiononClick={() => (myWixClient.auth.loggedIn() ? logout() : login())}><h3>Hello{' '}{myWixClient.auth.loggedIn()? member.profile?.nickname || member.profile?.slug || '': 'visitor'},</h3><span>{myWixClient.auth.loggedIn() ? 'Logout' : 'Login'}</span></section>)}</div>);}
Copy Code
import Cookies from 'js-cookie';import { useEffect, useState } from 'react';import { createClient, OAuthStrategy } from '@wix/sdk';const myWixClient = createClient({auth: OAuthStrategy({clientId: `10c1663b-2cdf-47c5-a3ef-30c2e8543849`,tokens: JSON.parse(Cookies.get('session') || null),}),});export default function LoginCallback() {const [nextPage, setNextPage] = useState(null);const [errorMessage, setErrorMessage] = useState(null);async function verifyLogin() {const data = JSON.parse(localStorage.getItem('oauthRedirectData'));localStorage.removeItem('oauthRedirectData');try {const { code, state } = myWixClient.auth.parseFromUrl();let tokens = await myWixClient.auth.getMemberTokens(code, state, data);while (!tokens?.refreshToken?.value) {// temporary workaroundtokens = await myWixClient.auth.getMemberTokens(code, state, data);}Cookies.set('session', JSON.stringify(tokens));window.location = data?.originalUri || '/';} catch (e) {setNextPage(data?.originalUri || '/');setErrorMessage(e.toString());}}useEffect(() => {verifyLogin();}, []);return (<article>{errorMessage && (<><span>{errorMessage}</span><br /><br /></>)}{nextPage ? <a href={nextPage}>Continue</a> : <>Loading...</>}</article>);}
Copy Code
import { createClient, OAuthStrategy } from '@wix/sdk';import { NextResponse } from 'next/server';export async function middleware(request) {// generate a session for the visitor if no session existsif (!request.cookies.get('session')) {const response = NextResponse.next();const myWixClient = createClient({auth: OAuthStrategy({ clientId: `10c1663b-2cdf-47c5-a3ef-30c2e8543849` }),});response.cookies.set('session',JSON.stringify(await myWixClient.auth.generateVisitorTokens()));return response;}}