0.13.0 • Published 2 months ago

@epfl-si/react-appauth v0.13.0

Weekly downloads
-
License
ISC
Repository
github
Last release
2 months ago

@epfl-si/react-appauth

An unopinionated React binding for @openid/appauth.

Feature Overview

  • Browser-side OpenID-Connect implementation, meaning all the backend server has left to do is validate bearer tokens with the OIDC identity provider (IdP)
    • Redirects the browser to the authorization server for the login operation
    • When redirected back, consumes (and cleans out) the code=, state=, error= and session_state= parts from the URL bar, regardless of whether they are found before or after the hash mark and whether the login operation was successful
    • Obtains OAuth2 tokens using fetch, not jQuery
    • Schedules access token refresh a few seconds before it expires
  • Brings out the best in @openid/appauth's underlying feature set
    • Uses the modern and secure OAuth2 authorization code flow
    • (Untested) Supports extra redirect parameters, to activate features such as user consent in authentication servers that support them
    • PKCE support
  • Supports cookie-less, local-storage-less operation
    • This is in fact the default mode (unlike in @openid/appauth)
    • Obviously, this has a cost with respect to security: no state= validation, PKCE is disabled
  • Straightforward, unopinionated React bindings
    • <OIDCContext> to pass in configuration and consume “back-office” events (i.e. access tokens)
    • useOpenIDConnectContext React hook to consume “front-office” events (for the appearance of widgets such as the login button and the “hello, ${user}” widget)
    • Fully unmount-proof: when the <OIDCContext> unmounts or changes its props, pending token refresh timers get canceled and callbacks stop calling back.
  • Demo app
    • ... With a Ruby back-end. But easy enough to set up with no prior knowledge
    • Comes with Keycloak-in-a-container, fully configured out of the box with test realm and user
  • Tested with Keycloak (see above)

How to Use

The various React components (“widgets”) discussed below must be placed within an <OIDCContext> near the top of your app, for instance:

import { OIDCContext } from "@epfl-si/react-appauth";

export function App() {
  return <OIDCContext authServerUrl = { "http://localhost:8080/realm/myrealm/" }
               debug = { true }
               client = { { clientId: "myclient" } }
               onNewToken={(token) => setFetchHeader("Authorization", `Bearer ${token}`)}
               onLogout={() => setFetchHeader("Authorization", null)}>
      <LoginButton/>
      <TheRestOfMyApp/>
      </OIDCContext>;
}

function setFetchHeader (header, value) {
  // ... Integrate with your backend API code here
}

@epfl-si/react-appauth exports a ready-made <LoginButton/> React element, but you could just as well reimplement it like this:

import { useOpenIDConnectContext, StateEnum as OIDCState } from "@epfl-si/react-appauth";

export function LoginButton () {
  const oidc = useOpenIDConnectContext();

  if (oidc.state === OIDCState.InProgress) {
    return <button title="Please wait..." disabled>⌛</button>;
  }

  const loggedIn = oidc.state === OIDCState.LoggedIn,
  action = loggedIn ? "Logout" : "Login",
  label = (oidc.error === undefined) ? action : [action, <sup>⚠</sup>],
  tooltip = oidc.error             ? `${oidc.error}` :
    loggedIn ? "Log out" : "Log in with OpenID-Connect";

  function onClick() {
    if (loggedIn) {
      oidc.logout();
    } else {
      oidc.login();
    }
  }

    return <button title={tooltip} onClick={onClick}>{label}</button>;
}

If you would like a “hello, user” widget, you will find a couple of building parts in src/sundry-widgets.tsx that could come in handy. For instance:

import { IfOIDCState, StateEnum, LoggedInUser } from "@epfl-si/react-appauth";

function HelloUser () {
  return <IfOIDCState is={ StateEnum.LoggedIn }>
    <p>Welcome, <LoggedInUser field="preferred_username" />!</p>
  </IfOIDCState>
}

But again, you could just implement it yourself out of useOIDCContext:

function HelloUser () {
  const oidc = useOpenIDConnectContext();
  if (! oidc.idToken) return <></>;
  return <p>Welcome, { oidc.idToken.preferred_username! }</p>
}

Reference manual

See API.md on GitHub

0.12.0

2 months ago

0.13.0

2 months ago

0.11.0

8 months ago

0.11.1

8 months ago

0.10.0

1 year ago

0.9.0

1 year ago

0.8.1

1 year ago

0.8.0

1 year ago

0.8.2

1 year ago

0.7.0

2 years ago

0.6.0

2 years ago

0.5.1

2 years ago

0.5.0

2 years ago

0.4.1

2 years ago

0.4.0

2 years ago

0.3.0

2 years ago

0.2.2

2 years ago

0.2.1

2 years ago

0.2.0

2 years ago

0.1.6

2 years ago

0.1.5

2 years ago

0.1.5-rc1

2 years ago

0.1.4

2 years ago

0.1.3

2 years ago

0.1.3-rc1

2 years ago

0.1.2

2 years ago

0.1.1

2 years ago

0.1.0

2 years ago