Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/authts/react-oidc-context

Lightweight auth library based on oidc-client-ts for React single page applications (SPA). Support for hooks and higher-order components (HOC).
https://github.com/authts/react-oidc-context

hooks oidc oidc-client react reactjs spa typescript

Last synced: about 5 hours ago
JSON representation

Lightweight auth library based on oidc-client-ts for React single page applications (SPA). Support for hooks and higher-order components (HOC).

Awesome Lists containing this project

README

        

# react-oidc-context

[![Stable Release](https://img.shields.io/npm/v/react-oidc-context.svg)](https://npm.im/react-oidc-context)
[![CI](https://github.com/authts/react-oidc-context/actions/workflows/ci.yml/badge.svg)](https://github.com/authts/react-oidc-context/actions/workflows/ci.yml)
[![Codecov](https://img.shields.io/codecov/c/github/authts/react-oidc-context)](https://app.codecov.io/gh/authts/react-oidc-context)

Lightweight auth library using the
[oidc-client-ts](https://github.com/authts/oidc-client-ts) library for React
single page applications (SPA). Support for
[hooks](https://reactjs.org/docs/hooks-intro.html) and
[higher-order components (HOC)](https://reactjs.org/docs/higher-order-components.html).

## Table of Contents

- [Documentation](#documentation)
- [Installation](#installation)
- [Getting Started](#getting-started)
- [Contributing](#contributing)
- [Influences](#influences)
- [License](#license)

## Documentation

This library implements an auth context provider by making use of the
`oidc-client-ts` library. Its configuration is tight coupled to that library.

- [oidc-client-ts](https://github.com/authts/oidc-client-ts)

The
[`User`](https://authts.github.io/oidc-client-ts/classes/User.html)
and
[`UserManager`](https://authts.github.io/oidc-client-ts/classes/UserManager.html)
is hold in this context, which is accessible from the
React application. Additionally it intercepts the auth redirects by looking at
the query/fragment parameters and acts accordingly. You still need to setup a
redirect uri, which must point to your application, but you do not need to
create that route.

To renew the access token, the
[automatic silent renew](https://authts.github.io/oidc-client-ts/interfaces/UserManagerSettings.html#automaticSilentRenew)
feature of `oidc-client-ts` can be used.

## Installation

Using [npm](https://npmjs.org/)

```bash
npm install oidc-client-ts react-oidc-context --save
```

Using [yarn](https://yarnpkg.com/)

```bash
yarn add oidc-client-ts react-oidc-context
```

## Getting Started

Configure the library by wrapping your application in `AuthProvider`:

```jsx
// src/index.jsx
import React from "react";
import ReactDOM from "react-dom";
import { AuthProvider } from "react-oidc-context";
import App from "./App";

const oidcConfig = {
authority: "",
client_id: "",
redirect_uri: "",
// ...
};

ReactDOM.render(


,
document.getElementById("app")
);
```

Use the `useAuth` hook in your components to access authentication state
(`isLoading`, `isAuthenticated` and `user`) and authentication methods
(`signinRedirect`, `removeUser` and `signOutRedirect`):

```jsx
// src/App.jsx
import React from "react";
import { useAuth } from "react-oidc-context";

function App() {
const auth = useAuth();

switch (auth.activeNavigator) {
case "signinSilent":
return

Signing you in...
;
case "signoutRedirect":
return
Signing you out...
;
}

if (auth.isLoading) {
return

Loading...
;
}

if (auth.error) {
return

Oops... {auth.error.message}
;
}

if (auth.isAuthenticated) {
return (


Hello {auth.user?.profile.sub}{" "}
void auth.removeUser()}>Log out

);
}

return void auth.signinRedirect()}>Log in;
}

export default App;
```

You **must** provide an implementation of `onSigninCallback` to `oidcConfig` to remove the payload from the URL upon successful login. Otherwise if you refresh the page and the payload is still there, `signinSilent` - which handles renewing your token - won't work.

A working implementation is already in the code [here](https://github.com/authts/react-oidc-context/blob/f175dcba6ab09871b027d6a2f2224a17712b67c5/src/AuthProvider.tsx#L20-L30).

### Use with a Class Component

Use the `withAuth` higher-order component to add the `auth` property to class
components:

```jsx
// src/Profile.jsx
import React from "react";
import { withAuth } from "react-oidc-context";

class Profile extends React.Component {
render() {
// `this.props.auth` has all the same properties as the `useAuth` hook
const auth = this.props.auth;
return

Hello {auth.user?.profile.sub}
;
}
}

export default withAuth(Profile);
```

### Call a protected API

As a child of `AuthProvider` with a user containing an access token:

```jsx
// src/Posts.jsx
import React from "react";
import { useAuth } from "react-oidc-context";

const Posts = () => {
const auth = useAuth();
const [posts, setPosts] = React.useState(Array);

React.useEffect(() => {
(async () => {
try {
const token = auth.user?.access_token;
const response = await fetch("https://api.example.com/posts", {
headers: {
Authorization: `Bearer ${token}`,
},
});
setPosts(await response.json());
} catch (e) {
console.error(e);
}
})();
}, [auth]);

if (!posts.length) {
return

Loading...
;
}

return (


    {posts.map((post, index) => {
    return
  • {post}
  • ;
    })}

);
};

export default Posts;
```

As **not** a child of `AuthProvider` (e.g. redux slice) when using local storage
(`WebStorageStateStore`) for the user containing an access token:

```jsx
// src/slice.js
import { User } from "oidc-client-ts"

function getUser() {
const oidcStorage = localStorage.getItem(`oidc.user::`)
if (!oidcStorage) {
return null;
}

return User.fromStorageString(oidcStorage);
}

export const getPosts = createAsyncThunk(
"store/getPosts",
async () => {
const user = getUser();
const token = user?.access_token;
return fetch("https://api.example.com/posts", {
headers: {
Authorization: `Bearer ${token}`,
},
});
},
// ...
)
```

### Protect a route

Secure a route component by using the `withAuthenticationRequired` higher-order component. If a user attempts
to access this route without authentication, they will be redirected to the login page.

```jsx
import React from 'react';
import { withAuthenticationRequired } from "react-oidc-context";

const PrivateRoute = () => (

Private
);

export default withAuthenticationRequired(PrivateRoute, {
OnRedirecting: () => (

Redirecting to the login page...
)
});
```

### Adding event listeners

The underlying [`UserManagerEvents`](https://authts.github.io/oidc-client-ts/classes/UserManagerEvents.html) instance can be imperatively managed with the `useAuth` hook.

```jsx
// src/App.jsx
import React from "react";
import { useAuth } from "react-oidc-context";

function App() {
const auth = useAuth();

React.useEffect(() => {
// the `return` is important - addAccessTokenExpiring() returns a cleanup function
return auth.events.addAccessTokenExpiring(() => {
if (alert("You're about to be signed out due to inactivity. Press continue to stay signed in.")) {
auth.signinSilent();
}
})
}, [auth.events, auth.signinSilent]);

return void auth.signinRedirect()}>Log in;
}

export default App;
```

### Automatic sign-in

Automatically sign-in and silently reestablish your previous session, if you close the tab and reopen the application.

```jsx
// index.jsx
const oidcConfig: AuthProviderProps = {
...
userStore: new WebStorageStateStore({ store: window.localStorage }),
};
```

```jsx
// src/App.jsx
import React from "react";
import { useAuth, hasAuthParams } from "react-oidc-context";

function App() {
const auth = useAuth();
const [hasTriedSignin, setHasTriedSignin] = React.useState(false);

// automatically sign-in
React.useEffect(() => {
if (!hasAuthParams() &&
!auth.isAuthenticated && !auth.activeNavigator && !auth.isLoading &&
!hasTriedSignin
) {
auth.signinRedirect();
setHasTriedSignin(true);
}
}, [auth, hasTriedSignin]);

if (auth.isLoading) {
return

Signing you in/out...
;
}

if (!auth.isAuthenticated) {
return

Unable to log in
;
}

return void auth.removeUser()}>Log out;
}

export default App;
```

## Contributing

We appreciate feedback and contribution to this repo!

## Influences

This library is inspired by [oidc-react](https://github.com/bjerkio/oidc-react),
which lacks error handling and
[auth0-react](https://github.com/auth0/auth0-react), which is focused on auth0.

## License

This project is licensed under the MIT license. See the
[LICENSE](https://github.com/authts/react-oidc-context/blob/main/LICENSE) file
for more info.