This is a React hook to manage the authentication state of your app.
const authentication = useAuthentication(authorizationId);
buildAuthentication()
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,
});
storage
StorageAdapter
secureStorage
StorageAdapter optional
storage
adapter will be used for everything.useAuthentication()
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 />;
}
}
appIconUrl
string optional
authorizationId
string optional
This hook returns an AuthenticationState
object.
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.AuthenticationState
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."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."authenticated"
identity
StoreIdentity
Identity of the authenticated user. It exposes the following properties:
entityRecord
: The user’s EntityRecord
client
: A Client
to interact with the user’s server.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()
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>
</>
);
}
authorizationId
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.
}
}