Integration with Client-side Javascript

In addition to the LoginRocket hosted experience (LoginRocket Web), LoginRocket also offers an API to allow you to integrate LoginRocket functionality directly into your frontend app.

Wherever possible, we strongly encourage getting AuthRocket working with your backend app first by using LoginRocket Web. Then, with the backend integration in place, come back and build a direct integration for your frontend app. This guide does assume that your backend integration is already working.

This guide does not require any specific SPA (or an SPA at all), but should be adjustable to fit your SPA of choice. If you’re using something else like Stimulus or jQuery, or even plain Javascript, that will also work just fine.

Install the loginrocket npm

Use npm or yarn to add LoginRocket to your project:

npm install @authrocket/loginrocket
yarn add @authrocket/loginrocket

Get your LoginRocket URL

In the AuthRocket management portal, go to Realm -> Integration -> LoginRocket API, and then select “Javascript”.

Keep this page open—you’ll need the information here in the next step.

Configuring the npm

Start by initializing the client. Since your LoginRocket URL is public anyway, it’s perfectly safe to commit this to your git repos.

import LoginRocket from '@authrocket/loginrocket'
const loginrocket = new LoginRocket({
  url: 'https://SAMPLE.e2.loginrocket.com/'
})

Logins

Let’s start by building a simple login form with fields for Email and Password. This is a very basic example. Feel free to modify to fit your SPA or other JS, CSS, or HTML frameworks.

<p id="lr-messages"></p>
<form id="login-form" action="#">
  <input id="email" type="text" placeholder="Email">
  <input id="password" name="" type="password" placeholder="Password">
  <button type="submit">Login</button>
</form>

Next, we’ll add an event handler function and attach it to the login button.

function handleLogin(event) {
  event.preventDefault()
  loginrocket.login({
    email: document.querySelector('#email').value,
    password: document.querySelector('#password').value
  }).then(processResponse)
}

document.querySelector('#login-form').addEventListener('submit', handleLogin)

All LoginRocket functions return Promises. They are also async/await compatible if that works better for you.

LoginRocket returns uniform responses regardless of which operation or API request is being executed. This simplifies your code by allowing you to use a unified response handler function. We already referenced such a unified function above as processResponse. Let’s define that now too.

function processResponse(response) {
  // We save the session ID and account/org ID here so they're available for logout
  //   and certain conditional_login operations later. For authenticating your
  //   frontend to your backend, see arToken below.
  if (response.session)
    window.sessionStorage.arSession = response.session
  if (response.account)
    window.sessionStorage.arAccount = response.account

  switch (response.result) {
    case 'need_mfa':
      // HEADS UP: If using MFA, you will likely want to show your own MFA form here.
      //   Until then, you can let LR Web handle it for you.
      // showMfaFormUsingToken(response.token)
      window.location = lrLocation('/login/verify', {token: response.token})
      break

    case 'conditional_login':
      // You may directly handle some, all, or none of these login conditions.
      // The default lets LR Web handle them for you.
      // See the LoginRocket API docs for more details.
      switch (response.conditions[0]) {
        // case 'account_inactive':
        // case 'must_complete_profile':
        // case 'must_create_account':
        // case 'must_setup_totp':
        // case 'must_verify_email':
        // case 'no_account_selected':
        default:
          window.location = lrLocation('/session', {
            redirect_uri: window.location,
            session: window.sessionStorage.arSession,
            account: window.sessionStorage,arAccount
          })
      }
      break

    case 'full_login':
      // If your frontend make API calls to your backend and needs to authenticate
      //   itself, use the stored arToken.
      window.sessionStorage.arToken = response.token

      // If your backend is session-less and always relies on the frontend submitting
      //   arToken, then token= may be dropped here. In that case, you may wish to
      //   redirect to /dashboard or another preferred page instead.
      // CHANGEME: If your backend does need to store the login token, then make this
      //   match the Default Login URL as configured inside AuthRocket.
      //   Update this  ---v  as appropriate.
      window.location = `/login?token=${response.token}`
      break

    case 'okay':
      document.querySelector('#lr-messages').innerText = response.message
      break

    case 'error':
      document.querySelector('#lr-messages').innerText = response.error
      break

    default:
      // This should be limited to network errors or similar. If you encounter an
      // error from loginrocket.js itself, please submit a bug report.
      console.error('Unexpected response', response)
  }
}

function lrLocation(path, params) {
  let u = new URL(loginrocket.lrUrl)
  u.pathname = path
  if (params)
    u.search = new URLSearchParams(params)
  return u
}

That’s a long one! The good news is it covers just about everything needed and will greatly expedite the rest of your integration. The only exception we’ll make is for logouts, as shown below.

Signups

Next, let’s look at signups. Depending on your needs, the signup form may need additional fields, but is otherwise basically the same as the login form. See the Signup API for available fields.

The signup request is also quite similar. As you can see, we’re reusing processResponse.

function handleSignup(event) {
  event.preventDefault()
  loginrocket.signup({
    email: document.querySelector('#email').value,
    password: document.querySelector('#password').value
  }).then(processResponse)
}

Logouts

To properly logout, it’s important to delete the login token from everywhere it was stored, plus inform AuthRocket that the session has ended.

Because ending sessions is quite different from starting or managing them, this is the one place where it’s easier to not use processResponse. So, that’s what we’ll demonstrate here.

<a href="#" id="logout">Logout</a>
function handleLogout(event) {
  event.preventDefault()
  loginrocket.logout({
    session: window.sessionStorage.arSession
  }).then(response => {
    // If your backend stores the login token in a session, that token needs to be
    // deleted somehow. One option is to make a backend API call (and do so before
    // deleting the local copy of the token.)
    // backendLogout()

    // Always clear the local copy of the token.
    window.sessionStorage.arToken = null

    // Always delete the session ID.
    window.sessionStorage.arSession = null

    // Instead of a backend API call above, another option is to add a logout route
    // which then deletes the login token from the session.
    // window.location = '/logout'
    // Otherwise, redirecting back to the root path or rerendering may be sufficient.
    window.location = '/'
  })
}

document.querySelector('#logout').addEventListener('click', handleLogout)

What’s next

There are a number of other operations you may wish to build into your app by using loginrocket.js, such as Verify a 2FA login (if 2FA is enabled), Forgot password, updating passwords and profiles, and more.

While you may wish to bring everything directly into your app, it’s also practical (and efficient) to let LR Web perform some or all of them for you. The choice is yours.

To continue integrating other operations, see the LoginRocket API.

If you’re stuck, let us know how we can help.