> ## Documentation Index
> Fetch the complete documentation index at: https://auth0.com/llms.txt
> Use this file to discover all available pages before exploring further.

> How to migrate single page applications from Auth0.js to Auth0 Single Page App SDK

# Migrate from Auth0.js to the Auth0 Single Page App SDK

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASKED*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

In this article, you’ll see how to migrate your single page app (SPA) from [auth0.js](/docs/libraries/auth0js) to [auth0-spa-js](/docs/libraries/auth0-single-page-app-sdk). Listed below are scenarios using auth0.js and the equivalent auth0-spa-js code.

## Functionality that cannot be migrated

Not all auth0.js functionality can be directly migrated to auth0-spa-js. Scenarios that cannot be directly migrated include:

* embedded [login with username/password](https://auth0.github.io/auth0.js/WebAuth.html#login) as well as embedded [passwordless login](https://auth0.github.io/auth0.js/WebAuth.html#passwordlessLogin)
* user [signup](https://auth0.github.io/auth0.js/WebAuth.html#signup)
* [get a user profile from /userinfo endpoint](https://auth0.github.io/auth0.js/Authentication.html#userInfo)
* [request an email to change the user's password](https://auth0.github.io/auth0.js/WebAuth.html#changePassword)
* [link users with the Management API](https://auth0.github.io/auth0.js/Management.html#linkUser)
* [get user with the Management API](https://auth0.github.io/auth0.js/Management.html#getUser)
* [update user attributes with the Management API](https://auth0.github.io/auth0.js/Management.html#patchUserAttributes)
* [update user metadata with the Management API](https://auth0.github.io/auth0.js/Management.html#patchUserMetadata)
* There are also some options that are configurable in Auth0.js that do not have a counterpart in the auth0-spa-js. An example of this is `responseType`. There is a reason that there is not a direct 1:1 mapping for each option. In this case, `responseType` is unnecessary, because the SDK is only for use in SPAs, and so one would not need to change the response type.

## Authentication Parameters are not modified anymore

Auth0.js converts custom parameters you set from `camelCase` to `snake_case` internally. For example, if you set `deviceType: 'offline'`, auth0.js actually sends `device_type: 'offline'` to the server.

When using auth0-spa-js, custom parameters **are not converted** from `camelCase` to `snake_case`. It will relay whatever parameter you send to the <Tooltip tip="Authorization Server: Centralized server that contributes to defining the boundaries of a user’s access. For example, your authorization server can control the data, tasks, and features available to a user." cta="View Glossary" href="/docs/glossary?term=authorization+server">authorization server</Tooltip>.

## Create the client

### auth0.js

* [WebAuth](https://auth0.github.io/auth0.js/WebAuth.html)

export const codeExample1 = `import { WebAuth } from 'auth0.js';

window.addEventListener('load', () => {
  var auth0 = new WebAuth({
    domain: '{yourDomain}',
    clientID: '{yourClientId}',
    redirectUri: 'https://YOUR_APP/callback'
  });
});`;

<AuthCodeBlock children={codeExample1} language="jsx" />

### auth0-spa-js

* [createAuth0Client()](https://auth0.github.io/auth0-spa-js/classes/Auth0Client.html#constructor)
* [Auth0ClientOptions](https://auth0.github.io/auth0-spa-js/interfaces/Auth0ClientOptions.html)

export const codeExample2 = `import createAuth0Client from '@auth0/auth0-spa-js';

window.addEventListener('load', () => {
  const auth0 = await createAuth0Client({
    domain: '{yourDomain}',
    client_id: '{yourClientId}',
    redirect_uri: 'https://YOUR_APP/callback'
  });
});`;

<AuthCodeBlock children={codeExample2} language="js" />

## Redirect to the Universal Login Page

### auth0.js

* [authorize()](https://auth0.github.io/auth0.js/WebAuth.html#authorize)

```jsx lines theme={null}
document.getElementById('login').addEventListener('click', () => {
  auth0.authorize();
});
```

### auth0-spa-js

* [Auth0Client.loginWithRedirect()](https://auth0.github.io/auth0-spa-js/classes/Auth0Client.html#loginWithRedirect)
* [RedirectLoginOptions](https://auth0.github.io/auth0-spa-js/interfaces/RedirectLoginOptions.html)

```jsx lines theme={null}
document.getElementById('login').addEventListener('click', async () => {
  await auth0.loginWithRedirect();
});
```

## Parse the hash after the redirect

### auth0.js

* [parseHash()](https://auth0.github.io/auth0.js/WebAuth.html#parseHash)

```jsx lines theme={null}
window.addEventListener('load', () => {
  auth0.parseHash({ hash: window.location.hash }, function(err, authResult) {
    if (err) {
      return console.log(err);
    }
    console.log(authResult);
  });
});
```

### auth0-spa-js

* [Auth0Client.handleRedirectCallback()](https://auth0.github.io/auth0-spa-js/classes/Auth0Client.html#handleRedirectCallback)

```jsx lines theme={null}
window.addEventListener('load', async () => {
  await auth0.handleRedirectCallback();
});
```

## Get the user information

### auth0.js

The `userInfo()` function makes a call to the [`/userinfo` endpoint](https://auth0.com/docs/api/authentication#user-profile) and returns the user profile.

* [userInfo()](https://auth0.github.io/auth0.js/Authentication.html#userInfo)

```jsx lines theme={null}
window.addEventListener('load', () => {
  auth0.client.userInfo(accessToken, function(err, user) {
    console.log(user)
  });
});
```

### auth0-spa-js

Unlike auth0.js, the Auth0 SPA SDK does not call to the [`/userinfo` endpoint](https://auth0.com/docs/api/authentication#user-profile) for the user profile. Instead `Auth0Client.getUser()` returns user information from the decoded `id_token`.

* [Auth0Client.getUser()](https://auth0.github.io/auth0-spa-js/classes/Auth0Client.html#getUser)

```jsx lines theme={null}
window.addEventListener('load', async () => {
  const user = await auth0.getUser();
  console.log(user);
});
```

## Open the Universal Login Page in a popup

### auth0.js

```jsx lines theme={null}
document.getElementById('login').addEventListener('click', () => {
  auth0.popup.authorize();
});
```

### auth0-spa-js

* [Auth0Client.loginWithPopup()](https://auth0.github.io/auth0-spa-js/classes/Auth0Client.html#loginWithPopup)
* [PopupLoginOptions](https://auth0.github.io/auth0-spa-js/interfaces/PopupLoginOptions.html)

```jsx lines theme={null}
document.getElementById('login').addEventListener('click', async () => {
  await auth0.loginWithPopup();
});
```

## Refresh tokens

### auth0.js

* [checkSession()](https://auth0.github.io/auth0.js/WebAuth.html#checkSession)

```jsx lines theme={null}
document.getElementById('login').addEventListener('click', () => {
  auth0.checkSession({}, function(err, authResult) {
    // Authentication tokens or error
  });
});
```

### auth0-spa-js

The Auth0 SPA SDK handles <Tooltip tip="Access Token: Authorization credential, in the form of an opaque string or JWT, used to access an API." cta="View Glossary" href="/docs/glossary?term=Access+Token">Access Token</Tooltip> refresh for you. Every time you call `getTokenSilently`, you'll either get a valid Access Token or an error if there's no session at Auth0.

* [Auth0Client.getTokenSilently()](https://auth0.github.io/auth0-spa-js/classes/Auth0Client.html#getTokenSilently)

```jsx lines theme={null}
document.getElementById('login').addEventListener('click', async () => {
  await auth0.getTokenSilently();
});
```

## Get a token for a different audience or with more scopes

### auth0.js

* [checkSession()](https://auth0.github.io/auth0.js/WebAuth.html#checkSession)

```jsx lines theme={null}
document.getElementById('login').addEventListener('click', () => {
  auth0.checkSession({
    audience: 'https://mydomain/another-api/',
    scope: 'read:messages'
  }, function(err, authResult) {
    // Authentication tokens or error
  });
});
```

### auth0-spa-js

The Auth0 SPA SDK handles Access Token refresh for you. Every time you call `getTokenSilently`, you'll either get a valid Access Token or an error if there's no session at Auth0.

* [Auth0Client.getTokenSilently()](https://auth0.github.io/auth0-spa-js/classes/Auth0Client.html#getTokenSilently)
* [GetTokenSilentlyOptions](https://auth0.github.io/auth0-spa-js/interfaces/GetTokenSilentlyOptions.html)

```jsx lines theme={null}
document.getElementById('login').addEventListener('click', async () => {
  await auth0.getTokenSilently({
    audience: 'https://mydomain/another-api/',
    scope: 'read:messages'
  });
});
```

Use [getTokenWithPopup](https://auth0.github.io/auth0-spa-js/classes/Auth0Client.html#getTokenWithPopup) to open a popup and allow the user to consent to the new API:

```jsx lines theme={null}
document.getElementById('login').addEventListener('click', async () => {
  await auth0.getTokenWithPopup({
    audience: 'https://mydomain/another-api/',
    scope: 'read:messages'
  });
});
```
