> Portal Navigation:
> 
> - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version.
> - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages).
> - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`).
> - Top-level index of all portals: https://dev.wix.com/docs/llms.txt
> - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt

## Resource: Quick Start

## Article: Quick Start

## Article Link: https://dev.wix.com/docs/go-headless/self-managed-headless/tutorials/java-script-sdk-tutorials/quick-start.md

## Article Content:

# Quick Start

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](https://dev.wix.com/docs/sdk.md).

For detailed instructions for managing visitors and members, see [Authenticate Visitors (JS SDK)](https://dev.wix.com/docs/go-headless/authentication/visitors/authenticate-visitors-js-sdk.md), [Add a Wix Login Page (JS SDK)](https://dev.wix.com/docs/go-headless/authentication/members/wix-login-page/add-a-wix-login-page-js-sdk.md), [Build a Custom Login Page (JS SDK)](https://dev.wix.com/docs/go-headless/authentication/members/custom-login-page/build-a-custom-login-page-js-sdk.md), and [Bring Your Own Identity Provider](https://dev.wix.com/docs/go-headless/authentication/members/identity-providers/bring-your-own-identity-provider.md).

> **Note:** If you build with [Wix's Astro integration](https://dev.wix.com/docs/go-headless/wix-managed-headless/about-the-astro-integration.md), you don't need to handle OAuth setup or create a client because it's done automatically. 

This tutorial shows you how to implement:

- A React component that handles login and logout by redirecting the visitor to a Wix-hosted page.
- A callback page that verifies login and saves member tokens in a cookie.
- [Next.js middleware](https://nextjs.org/docs/14/app/building-your-application/routing/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 this [example site](https://wix-headless-example.vercel.app). To get the code, fork the [Headless Templates repo](https://github.com/wix/headless-templates). The site code is under [minimal examples](https://github.com/wix/headless-templates/tree/main/nextjs/minimal-examples).

The site focuses on simplicity and understandability, rather than feature richness, performance or completeness. Looking for a more comprehensive example site integrating Wix Headless APIs? Check out our [starter templates](https://dev.wix.com/docs/go-headless/self-managed-headless/templates/next-js-templates.md).

> **Note:** The code in this tutorial is written in [JSX](https://react.dev/learn/writing-markup-with-jsx), but you can use the SDK in any JavaScript environment.

Implementing the session management flow includes the following steps:

1. Set up the Wix Headless environment.
1. Create a login component.
1. Create a callback page.
1. Create middleware for managing tokens.

## Step 1: Set up the Wix Headless environment

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:

1. If you haven't already, [create a project](https://dev.wix.com/docs/go-headless/self-managed-headless/get-started/create-a-self-managed-headless-project.md).
   When prompted to add functionalities to your new project, select whichever business solutions your project needs.
2. Set up authorization for your site by [creating and configuring](https://dev.wix.com/docs/go-headless/authentication/setup/set-up-a-headless-client.md) an OAuth app:  
   a. Create an OAuth app in your project's [Headless Settings](https://www.wix.com/my-account/site-selector/?buttonText=Select%20Site&title=Select%20a%20Site&autoSelectOnSingleSite=true&actionUrl=https:%2F%2Fwww.wix.com%2Fdashboard%2F%7B%7BmetaSiteId%7D%7D%2Foauth-apps-settings). Copy your Client ID - you'll need it later.  
   b. Configure Wix login page URLs as [allowed redirect domains](https://dev.wix.com/docs/go-headless/develop-your-project/wix-hosted-pages/add-allowed-redirect-domains.md) in your site dashboard.
3. Install the SDK client and relevant SDK module packages by running the following commands:

   For NPM:
   ```console
   npm install @wix/sdk
   npm install @wix/members
   ```
   For Yarn:
   ```console
   yarn add @wix/sdk
   yarn add @wix/members
   ```
4. Install the `react` package to handle UI rendering, the `js-cookie` package to handle session cookies, and the `next/server` package with helper functions for [Next.js middleware](https://nextjs.org/docs/14/app/building-your-application/routing/middleware).
 
   For NPM:
   ```console
   npm install react
   npm install js-cookie
   npm install next/server
   ```
   For Yarn:
   ```console
   yarn add react
   yarn add js-cookie
   yarn add next/server
   ```

## Step 2: Create a login component

Follow these steps to create a React component that handles login and logout by redirecting the visitor to a Wix-hosted page.

### 1. Import the SDK modules and create an SDK client

To set up the code file for the login component, follow these steps:

1. Add the following import statements to the top of your code file:

   ```jsx
   import { createClient, OAuthStrategy } from '@wix/sdk';
   import { members } from '@wix/members';
   import { useEffect, useState } from 'react';
   import Cookies from 'js-cookie';
   ```

1. 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**](https://www.wix.com/my-account/site-selector/?buttonText=Select%20Site&title=Select%20a%20Site&autoSelectOnSingleSite=true&actionUrl=https:%2F%2Fwww.wix.com%2Fdashboard%2F%7B%7BmetaSiteId%7D%7D%2Foauth-apps-settings).

   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.

   ```jsx
   const myWixClient = createClient({
     modules: { members },
     auth: OAuthStrategy({
       clientId: `<YOUR-CLIENT-ID>`,
       tokens: JSON.parse(Cookies.get('session') || null),
     }),
   });
   ```

### 2. Create a React component and a state variable

The logic for our example login request flow is contained in a React component called `LoginBar`. To create the component, follow these steps:

1. Define the component function as a default export in your code file:

   ```jsx
   export default function LoginBar() {}
   ```

1. Define a state variable by adding the following code in the component function:

   ```jsx
   const [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.

### 3. Define functions to handle member sessions

Add the following 3 functions for handling member sessions to the `LoginBar` component:

1. `fetchMember()` - Uses the SDK client's `auth.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.

   ```jsx
   async function fetchMember() {
     const { member } = myWixClient.auth.loggedIn()
       ? await myWixClient.members.getCurrentMember()
       : {};
     setMember(member || undefined);
   }
   ```

1. `login()` - Uses the SDK client's `auth.generateOAuthData()` and `auth.getAuthUrl()` functions to log in a site visitor. This function runs when a **Login** button in the rendered UI is clicked.

   ```jsx
   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;
   }
   ```

   The SDK client's `auth.generateOAuthData()` function generates the data needed for authorization, which is saved in local storage with the key `oauthRedirectData`. When the Wix-managed authentication process is over, Wix redirects the visitor to the URL provided in `redirectUri`. The `auth.getAuthUrl()` function returns a URL for a Wix-hosted authentication page called `authUrl`.

1. `logout()` - Uses the SDK client's `auth.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.

   ```jsx
   async function logout() {
     const { logoutUrl } = await myWixClient.auth.logout(window.location.href);
     Cookies.remove('session');
     window.location = logoutUrl;
   }
   ```

### 4. Add the `useEffect` hook

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.

```jsx
useEffect(() => {
  fetchMember();
}, []);
```

### 5. Render the UI

Add the following code to the `LoginBar` component function's `return` statement to render the UI.

```jsx
return (
  <div>
    {member !== null && (
      <section
        onClick={() => (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.

## Step 3: Create a callback page

Follow these steps to create a callback page for Wix to redirect the visitor to after handling authentication.

### 1. Import the SDK modules and create an SDK client

To set up the code file for the callback page, follow these steps:

1. Add the following import statements to the top of your code file:

   ```jsx
   import Cookies from 'js-cookie';
   import { useEffect, useState } from 'react';
   import { createClient, OAuthStrategy } from '@wix/sdk';
   ```

1. Create an SDK client by adding the following code to your code file:

   ```jsx
   const myWixClient = createClient({
     auth: OAuthStrategy({
       clientId: `<YOUR-CLIENT-ID>`,
       tokens: JSON.parse(Cookies.get('session') || null),
     }),
   });
   ```

### 2. Create a React component and state variables

The logic for our example login request flow is contained in a React component called `LoginCallback`. To create the component, follow these steps:

1. Define the component function as a default export in your code file:

   ```jsx
   export default function LoginCallback() {}
   ```

1. Define state variables by adding the following code in the component function:

   ```jsx
   const [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 the `errorMessage` state variable stores the error received if there is an error generating a member token.

### 3. Define a function to verify login

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 `/`.

```jsx
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());
  }
}
```

### 4. Add the `useEffect` hook

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.

```jsx
useEffect(() => {
  verifyLogin();
}, []);
```

### 5. Render the UI

Add the following code to the `LoginCallback` component function's `return` statement to render the UI.

```jsx
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...**.

## Step 4: Create middleware for managing tokens

Once you've implemented a login component and a callback page, follow these steps to create [Next.js middleware](https://nextjs.org/docs/14/app/building-your-application/routing/middleware) to check a visitor's session status when loading every page.

### 1. Import the SDK modules

To set up the code file for the session management middleware, follow these steps:

1. Add the following import statements to the top of your code file:

   ```jsx
   import { createClient, OAuthStrategy } from '@wix/sdk';
   import { NextResponse } from '/next/server';
   ```

### 2. Create a middleware function

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:

```js
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;
  }
}
```

## Complete code examples

You can use the following full code examples as a starting point for developing your own site:

### Login component

```jsx
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: `<YOUR-CLIENT-ID>`,
    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.getCurrentMember()
      : {};
    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 && (
        <section
          onClick={() => (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>
  );
}
```

### Callback page

```jsx
import Cookies from 'js-cookie';
import { useEffect, useState } from 'react';
import { createClient, OAuthStrategy } from '@wix/sdk';

const myWixClient = createClient({
  auth: OAuthStrategy({
    clientId: `<YOUR-CLIENT-ID>`,
    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 workaround
        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());
    }
  }

  useEffect(() => {
    verifyLogin();
  }, []);

  return (
    <article>
      {errorMessage && (
        <>
          <span>{errorMessage}</span>
          <br />
          <br />
        </>
      )}
      {nextPage ? <a href={nextPage}>Continue</a> : <>Loading...</>}
    </article>
  );
}
```

### Middleware

```js
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 exists
  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;
  }
}
```