> ## Documentation Index
> Fetch the complete documentation index at: https://docs-dev-actions-triggers-prototype.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> API and SPA Configuration for the SPA + API architecture scenario

# API and SPA Configuration (SPAs + API)

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 section we will see how we can implement an API for our scenario.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  For simplicity, we will keep our implementation solely focused on authentication and authorization. As you will see in the samples, the input timesheet entry will be hard-coded, and the API will not persist the timesheet entry. Instead, it will simply echo back some of the info.
</Callout>

## Define the API endpoints

First we need to define the endpoints of our API.

<Card title="What is an API endpoint?">
  An **API endpoint** is a unique URL that represents an object. To interact with this object, you need to point your application to its URL. For example, if you had an API that could return either orders or customers, you might configure two endpoints: `/orders` and `/customers`. Your application would interact with these endpoints using different HTTP methods; for example, `POST /orders` could create a new order or `GET /orders` could retrieve the dataset of one or more orders.
</Card>

For this implementation we will only define 2 endpoints; one for retrieving a list of all timesheets for an employee, and another which will allow an employee to create a new timesheet entry.

An `HTTP GET` request to the `/timesheets` endpoint will allow a user to retrieve their timesheets, and an `HTTP POST` request to the `/timesheets` endpoint will allow a user to add a new timesheet.

**See the implementation in** [**Node.js**](/docs/get-started/architecture-scenarios/spa-api/api-implementation-nodejs#1-define-the-api-endpoints).

### Secure the Endpoints

When an API receives a request with a bearer <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> as part of the header, the first thing to do is to validate the token. This consists of a series of steps, and if any of these fails then the request must be rejected with a `Missing or invalid token` error message to the calling app.

The validations that the API should perform are:

* Check that the <Tooltip tip="JSON Web Token (JWT): Standard ID Token format (and often Access Token format) used to represent claims securely between two parties." cta="View Glossary" href="/docs/glossary?term=JWT">JWT</Tooltip> is well formed
* Check the signature
* Validate the standard claims

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  [JWT.io](https://jwt.io/) provides a list of libraries that can do most of the work for you: parse the JWT, verify the signature and the claims.
</Callout>

Part of the validation process is to also check the Application permissions (scopes), but we will address this separately in the next paragraph of this document.

For more information on validating Access Tokens, see [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).

**See the implementation in** [**Node.js**](/docs/get-started/architecture-scenarios/spa-api/api-implementation-nodejs#2-secure-the-api-endpoints).

### Check the Application's Permissions

By now we have verified that the JWT is valid. The last step is to verify that the application has the permissions required to access the protected resources.

To do so, the API needs to check the [scopes](/docs/get-started/apis/scopes) of the decoded JWT. This claim is part of the payload and it is a space-separated list of strings.

**See the implementation in** [**Node.js**](/docs/get-started/architecture-scenarios/spa-api/api-implementation-nodejs#3-check-the-client-permissions).

### Determine user identity

For both endpoints (retrieving the list of timesheets, and adding a new timesheet) we will need to determine the identity of the user.

For retrieving the list of timesheets this is to ensure that we only return the timesheets belonging to the user making the request, and for adding a new timesheet this is to ensure that the timesheet is associated with the user making the request.

One of the standard JWT claims is the `sub` claim which identifies the principal that is the subject to the claim. In the case of the Implicit Grant flow this claim will contain the user's identity, which will be the unique identifier for the Auth0 user. You can use this to associate any information in external systems with a particular user.

You can also use a custom claim to add another attribute of the user - such as their email address - to the Access Token and use that to uniquely identify the user.

**See the implementation in** [**Node.js**](/docs/get-started/architecture-scenarios/spa-api/api-implementation-nodejs#4-determine-the-user-identity).

## Implement the SPA

In this section we will see how we can implement a SPA for our scenario.

### Authorize the user

To authorize the user we will be using the [auth0.js library](/docs/libraries/auth0js). You can initialize a new instance of the Auth0 application as follows:

export const codeExample = `var auth0 = new auth0.WebAuth({
  clientID: '{yourClientId}',
  domain: '{yourDomain}',
  responseType: 'token id_token',
  audience: 'YOUR_API_IDENTIFIER',
  redirectUri: '{https://yourApp/callback}',
  scope: 'openid profile read:timesheets create:timesheets'
});`;

<AuthCodeBlock children={codeExample} language="javascript" />

You need to pass the following configuration values:

* **clientID**: The value of your Auth0 <Tooltip tip="Client ID: Identification value given to your registered resource from Auth0." cta="View Glossary" href="/docs/glossary?term=Client+Id">Client Id</Tooltip>. You can retrieve it from the Settings of your Application at the [Dashboard](https://manage.auth0.com/#/applications%7D).
* **domain**: The value of your Auth0 Domain. You can retrieve it from the Settings of your Application at the [Dashboard](https://manage.auth0.com/#/applications%7D).
* **responseType**: Indicates the Authentication Flow to use. For a SPA which uses the **Implicit Flow**, this should be set to `token id_token`. The `token` part, triggers the flow to return an Access Token in the URL fragment, while the `id_token` part, triggers the flow to return an <Tooltip tip="ID Token: Credential meant for the client itself, rather than for accessing a resource." cta="View Glossary" href="/docs/glossary?term=ID+Token">ID Token</Tooltip> as well.
* **<Tooltip tip="Audience: Unique identifier of the audience for an issued token. Named aud in a token, its value contains the ID of either an application (Client ID) for an ID Token or an API (API Identifier) for an Access Token." cta="View Glossary" href="/docs/glossary?term=audience">audience</Tooltip>**: The value of your API Identifier. You can retrieve it from the [Settings of your API](https://manage.auth0.com/#/apis%7D) at the Dashboard.
* **redirectUri**: The URL to which Auth0 should redirect to after the user has authenticated.
* **scope**: The [scopes](/docs/get-started/apis/scopes) which determine the information to be returned in the ID Token and Access Token. A scope of `openid profile` will return all the user profile information in the ID Token. You also need to request the scopes required to call the API, in this case the `read:timesheets create:timesheets` scopes. This will ensure that the Access Token has these scopes.

To initiate the authentication flow you can call the `authorize()` method:

```js lines theme={null}
auth0.authorize();
```

After the authentication, Auth0 will redirect back to the **redirectUri** you specified when configuring the new instance of the Auth0 application. At this point you will need to call the `parseHash()` method which parses a URL hash fragment to extract the result of an Auth0 authentication response.

The contents of the authResult object returned by parseHash depend upon which authentication parameters were used. It may include the following:

* **idToken**: An ID Token JWT containing user profile information
* **accessToken**: An Access Token for the API, specified by the **audience**.
* **expiresIn**: A string containing the expiration time (in seconds) of the Access Token.

Determine where best to [store the tokens](/docs/secure/security-guidance/data-security/token-storage). If your single-page app has a backend server at all, then tokens should be handled server-side using the [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow) or [Authorization Code Flow with Proof Key for Code Exchange (PKCE)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce).

If you have a single-page app (SPA) with no corresponding backend server, your SPA should request new tokens on login and store them in memory without any persistence. To make API calls, your SPA would then use the in-memory copy of the token.

For an example of how to handle sessions in SPAs, check out the [Handle Authentication Tokens](/docs/quickstart/spa/vanillajs#handle-authentication-tokens) section of the [JavaScript Single-Page App Quickstart](/docs/quickstart/spa/vanillajs).

**See the implementation in** [**Angular 2**](/docs/get-started/architecture-scenarios/spa-api/spa-implementation-angular2#2-authorize-the-user).

### Get the User Profile

<Card title="Extract info from the token">
  This section shows how to retrieve the user info using the Access Token and the [/userinfo endpoint](https://auth0.com/docs/api/authentication#get-user-info). To avoid this API call, you can just decode the ID Token [using a library](https://jwt.io/#libraries-io) (make sure you validate it first). If you need additional user information consider using [our Management API](https://auth0.com/docs/api/management/v2#!/Users/get_users_by_id) from your backend.
</Card>

The `client.userInfo` method can be called passing the returned `authResult.accessToken` in order to retrieve the user's profile information. It will make a request to the [/userinfo endpoint](https://auth0.com/docs/api/authentication#get-user-info) and return the `user` object, which contains the user's information, similar to the example below:

```json lines theme={null}
{
    "email_verified": "false",
    "email": "test@example.com",
    "clientID": "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH",
    "updated_at": "2017-02-07T20:50:33.563Z",
    "name": "tester9@example.com",
    "picture": "https://gravatar.com/avatar/example.png",
    "user_id": "auth0|123456789012345678901234",
    "nickname": "tester9",
    "created_at": "2017-01-20T20:06:05.008Z",
    "sub": "auth0|123456789012345678901234"
}
```

You can access any of these properties in the callback function passed when calling the `userInfo` function:

```javascript lines theme={null}
const accessToken = authResult.accessToken;

auth0.client.userInfo(accessToken, (err, profile) => {
  if (profile) {
    // Get the user’s nickname and profile image
    var nickname = profile.nickname;
    var picture = profile.picture;
  }
});
```

**See the implementation in** [**Angular 2**](/docs/get-started/architecture-scenarios/spa-api/spa-implementation-angular2#3-get-the-user-profile).

### Display UI Elements Conditionally Based on Scope

Based on the `scope` of the user, you may want to show or hide certain UI elements. To determine the scope issued to a user, you will need to store the scope which was initially requested during the authorization process. When a user is authorized, the `scope` will also be returned in the `authResult`.

If the `scope` in the `authResult` is empty, then all the scopes which was requested was granted. If the `scope` in the `authResult` is not empty, it means a different set of scopes were granted, and you should use the ones in `authResult.scope`.

**See the implementation in** [**Angular 2**](/docs/get-started/architecture-scenarios/spa-api/spa-implementation-angular2#4-display-ui-elements-conditionally-based-on-scope).

### Call the API

To access secured resources from your API, the authenticated user's Access Token needs to be included in requests that are sent to it. This is accomplished by sending the Access Token in an `Authorization` header using the `Bearer` scheme.

**See the implementation in** [**Angular 2**](/docs/get-started/architecture-scenarios/spa-api/spa-implementation-angular2#5-call-the-api).

### Renew the Access Token

As a security measure, it is recommended that the lifetime of a user's Access Token be kept short. When you create an API in the <Tooltip tip="Auth0 Dashboard: Auth0's main product to configure your services." cta="View Glossary" href="/docs/glossary?term=Auth0+dashboard">Auth0 dashboard</Tooltip>, the default lifetime is `7200` seconds (2 hours), but this can be controlled on a per-API basis.

Once expired, an Access Token can no longer be used to access an API. In order to obtain access again, a new Access Token needs to be obtained.

Obtaining a new Access Token can be done by repeating the authentication flow, used to obtain the initial Access Token. In a SPA this is not ideal, as you may not want to redirect the user away from their current task to complete the authentication flow again.

In cases like this you can make use of [Silent Authentication](/docs/authenticate/login/configure-silent-authentication). Silent authentication lets you perform an authentication flow where Auth0 will only reply with redirects, and never with a login page. This does however require that the user was already logged in via [Single Sign-on (SSO)](/docs/authenticate/single-sign-on).

**See the implementation in** [**Angular 2**](/docs/get-started/architecture-scenarios/spa-api/spa-implementation-angular2#6-renew-the-access-token).
