React SDK

useAuthentication

This is a React hook to manage the authentication state of your app.

const authentication = useAuthentication(authorizationId);

Call buildAuthentication outside of your component to configure the hook.

import {buildAuthentication} from "../baq/authentication.js";
import {localStorageAdapter} from "@baqhub/sdk-react-dom";

const {useAuthentication} = buildAuthentication({
  storage: localStorageAdapter,
});

Options

  • storage StorageAdapter

    • Storage adapter to use for local authentication data.
  • secureStorage StorageAdapter optional

    • Storage adapter to use for the sensitive authentication private key. If not specified, the storage adapter will be used for everything.

Call useAuthentication at the top level of your component to manage the authentication lifecycle.

import {buildAuthentication} from "../baq/authentication.js";

const {useAuthentication} = buildAuthentication({...});

function App() {
  const authentication = useAuthentication();

  switch (authentication.status) {
    case "unauthenticated":
      return <LoginUI />;

    case "authenticated":
      return <AppUI />;
  }
}

Options

  • appIconUrl string optional

    • Publicly accessible URL of an image to use as the app icon when registering with the user’s server. See App Icons­ for more.
  • authorizationId string optional

    • String value returned by the user’s server in the redirect URL when the authentication flow completes. See Authentication Flow­ for more.

Returns

This hook returns an AuthenticationState­ object.

Notes

  • The useAuthentication hook should only be used once within a given React application as it does not synchronize state between instances. The resulting AuthenticationState can be passed to various components using Props and Context.
  • status enum

    • Current state of the authentication system. Other properties depend on this.

      • "unauthenticated": The current user is not authenticated.
      • "authenticated": The current user had a valid session with a BAQ server.

Properties when "unauthenticated"

  • connectStatus enum

    • Current state of the authentication form.

      • "idle": Awaiting entity input from the user.
      • "connecting": Connecting to the user’s server.
      • "waiting_on_flow": User needs to be redirected to their server’s authentication flow.
  • onConnectRequest(entity: string)

    • Initiate the authentication process.

      Only call when connectStatus="idle".

      Parameters:

      • entity string : The entity of the user to initiate the authentication process for.
  • error enum

    • An error that happened while initiating authentication with the user’s server.

      Only has a value when connectStatus="idle".

      • "entity_not_found": The provided entity could not be resolved.
      • "bad_app_record": The provided app record was refused by the server.
      • "other": Other server or network error.
  • flowUrl string

    • URL to redirect the user to for the next step of the authentication flow.

      Only has a value when connectStatus="waiting_on_flow".

  • onAuthorizationResult(authorizationId?: string)

    • Provide the result of the authentication flow.

      Only call when connectStatus="waiting_on_flow".

      This is only needed when the app was not restarted during the authentication flow (e.g. if it happened in a different window).

      Parameters:

      • authorizationId string optional : The string value returned by the user’s server in the redirect URL when the authentication flow completes. Can be undefined if the authorization failed.

Properties when "authenticated"

  • identity StoreIdentity

    • Identity of the authenticated user. It exposes the following properties:

      These can either be used directly to interact with the user’s server, or they can be provided to a Store­ to fully take advantage of the SDK when building the rest of the app.

  • disconnect()

    • A function to logout the current user.

Use the status to decide whether to display a login page or the app itself.

import {buildAuthentication} from "../baq/authentication.js";
import {localStorageAdapter} from "@baqhub/sdk-react-dom";

const {useAuthentication} = buildAuthentication({
  storage: localStorageAdapter,
});

function App() {
  const authentication = useAuthentication();

  switch (authentication.status) {
    case "unauthenticated":
    // Display login UI.

    case "authenticated":
    // Display app UI.
  }
}

When unauthenticated the properties of the AuthenticationState can be used to build a login form.

import {buildAuthentication} from "../baq/authentication.js";

const {useAuthentication} = buildAuthentication({...});

function App() {
  const authentication = useAuthentication();
  const [entity, setEntity] = useState("");

  if (authentication.status !== "unauthenticated") {
    // We're authenticated, yay!
    return;
  }

  // Redirect to the authentication flow when needed.
  useEffect(() => {
    if (authentication.connectStatus !== "waiting_on_flow") {
      return;
    }

    window.location.href = authentication.flowUrl;
  }, [authentication]);

  // Disable the connect button while connection is in progress.
  const canConnect = authentication.connectStatus === "idle";
  const onConnectClick = canConnect
    ? () => authentication.connectStart(entity)
    : undefined;

  return (
    <>
      <input value={entity} onChange={setEntity} />
      <button disabled={!canConnect} onClick={onConnectStart}>
        Connect
      </button>
    </>
  );
}

Assuming a redirect URL with the format /auth/{authorization_id}, here’s how the authorizationId could be parsed and provided to the hook.

import {buildAuthentication} from "../baq/authentication.js";
import {useConstant} from "@baqhub/sdk-react";

const {useAuthentication} = buildAuthentication({...});

const authPrefix = "/auth/";

function App() {
  const authorizationId = useConstant(() => {
    const url = new URL(window.location.href);
    if (!url.pathname.startsWith(authPrefix)) {
      return undefined;
    }

    return url.pathname.slice(authPrefix.length) || undefined;
  });

  const authentication = useAuthentication(authorizationId);
}

This is only one way to achieve this. How authorizationId is retrieved has been kept flexible to accommodate different hosting scenarios. Here are a few examples:

  • A backend server could retrieve the authorizationId from the URL and expose it directly in the HTML it generates.

  • A mobile app could register a custom scheme and use it to build the redirect URL. The app would then parse the authorizationId within it’s launch arguments. The same could apply to a desktop app.

  • The redirect URL could request for the authorizationId to be within the path, query, or hash, depending on what is most convenient for that particular app.

When configured with an asynchronous storage adapter, useAuthentication should be wrapped in a <Suspense> boundary to prevent errors and display loading UI while the storage is being accessed.

import {buildAuthentication} from "../baq/authentication.js";
import {
  asyncStorageAdapter,
  secureStorageAdapter,
} from "@baqhub/sdk-expo";

const {useAuthentication} = buildAuthentication({
  storage: asyncStorageAdapter,
  secureStorage: secureStorageAdapter,
});

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <AppContent />
    </Suspense>
  );
}

function Loading() {
  // Display loading UI.
}

function AppContent() {
  const authentication = useAuthentication();

  switch (authentication.status) {
    case "unauthenticated":
    // Display login UI.

    case "authenticated":
    // Display app UI.
  }
}
© 2024 Quentez