npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-auth-proxy

v0.7.0

Published

A turnkey solution for using authentication sessions in React built-in dev proxy.

Downloads

592

Readme

react-auth-proxy

Pipeline status

Dependencies License Package

A turnkey solution for using authentication sessions in React built-in dev proxy 🧪🛡️.

Philosophy

The package is intended to be lightweight and configurable to support most usual authentication flows.

From react official doc for custom dev proxy setup, developers need to create a setupProxy.js file, that exports a function registering middlewares on an express-like app.

The module registers middlewares to manage a testing 3rd party authentication flow:

  • redirection to a login page
  • storing user sessions
  • setting end-user session cookie
  • logout endpoint

Usage

Install

npm install react-auth-proxy

Create a setupProxy.js file with your business logic

As a developer, I want my webapp to authenticate to an API server via JWT in a bearer token.

setupProxy.js (in the same folder as index.js)

const reactAuthProxy = require('react-auth-proxy')
const jsonwebtoken = require('jsonwebtoken')

const config = {
  auth: {
    presetUser: { name: 'Carlo', role: 'account-manager' },
    encode: user => 'bearer ' + jsonwebtoken.sign(user, 'secret'),
  },
  proxy: {
    target: 'http://api-server:8080',
  },
}

module.exports = reactAuthProxy(config)

Then restart the react dev server.

Config fields

| Param Type | Default value | Description | | ---------------- | ------------- | ----------- | | auth.autoLogin bool | false | When true, automatically login as the first presetUser | | auth.encode function | JSON.stringify | takes a user as single param and encodes it into the header | | auth.headerName string | authorization | Name of the header consumed by the backend | | auth.loginPath string | /.auth/login | Path to get the login form HTML page | | auth.logoutPath string | /.auth/logout | Path to trigger the current user's session deletion | | auth.presetUser object or array or objects | {"name": "test"} | The user data to provide to the backend for security checks (RBAC) | | auth.redirectParamName string | redirect | Name of the query param carrying the url where to browse back after the login | | auth.serverPath string or array of strings | /local-server | Path to reach the server APIs | | auth.successPath string | /.auth/success | Path to get redirected for user creation after a successful login | | proxy object | {} | Config forwarded to the http-proxy-middleware module | | proxy.callback function | undefined | Called on the app, after all the registrations, used for custom registrations | | proxy.target string | http://localhost:8080 | Dev instance of the server hosting the APIs | | sessionCookie.name string | session | Name of the cookie stored on clend-side, holding the session ID value | | sessionCookie.maxAge int | 1000 * 60 * 60 * 24 * 7 = 1 week | Number of milliseconds the cookie remains valid |

Module exports and exposed functions

Default export: the proxy registerer constructor. Named export: the sessions storage object.

Exposed data:

  • the registerer merge of user config and default fields: config
  • the registerer core proxy middleware: tradeSessionForJwt
  • the registerer user extractor from the sessions, using the right cookie name: getUser.

Example

As a developer, I want my webapp to authenticate to an Azure App Service backend relying on Azure Active Directory.

The client only has access to a session ID stored in a cookie and an API Gateway trades it for a custom token on backend side.

setupProxy.js

const reactAuthProxy = require('react-auth-proxy')

const makeClaim = (typ, val) => ({typ, val})
function encodeMsUser(user) {
  const payload = {
    claims: [
      makeClaim('name', user.name),
      makeClaim('roles', user.role),
    ]
  }
  return Buffer.from(JSON.stringify(payload)).toString('base64')
}

const config = {
  auth: {
    presetUser: { name: 'Carlo', role: 'account-manager' },
    headerName: 'x-ms-client-principal',
    encode: encodeMsUser,
    serverPath: '/api-server/v1',
  },
  proxy: {
    target: 'http://api-server:8080',
  },
  sessionCookie: {
    name: 'aad-session-id',
    maxAge: 60000, // 1 minute
  },
}

module.exports = reactAuthProxy(config)

Get your React webapp redirected to a login page when the session has expired

Many of webapp developers rely on axios for API calls. Axios transparently follows the redirections during its calls, including the redirection to the login page that comes when the user session has expired.

To detect the login redirection, rely on the response content-type:

import axios from 'axios'

export const instance = axios.create({
  withCredentials: true,
  baseURL: 'api-server/v1',
  headers: {
    'content-type': 'application/json',
  },
})

const allowedRedirectDomains = [window.location.origin, "https://login.windows.net"]

instance.interceptors.response.use(
  resp => {
    const contentType = resp.headers['content-type']

    if(contentType.includes('text/html')
		&& allowedRedirectDomains.some(orig => resp.request.responseURL.startsWith(orig))) {
      console.log('Refresh for new credendials', resp.request.responseURL)
      const loginParams = new URLSearchParams()
      loginParams.set("redirect", window.location)

      const respUrl = new URL(resp.request.responseURL)
      respUrl.search = "?" + loginParams // Override any API ref
      window.location = respUrl
      return
    }
    return resp.data
  },
  error => {
    throw error
  }
)

Any API call witnessing an expired session will result in the whole webapp browsing to the login page and provide a redirect parameter to come back at the end of the authentication.

# Redirection after a logout The client can set a query param called post_logout_redirect_uri (same as Azure) when calling the logout so the proxy will redirect it to the given URL once the logout is done.

Flow sequence

sequenceDiagram
	participant b as Browser
	participant r as React Web App
	participant p as React Auth Proxy
	participant s as API server

	autonumber

  Note over b, s: No session yet

  b->>r: Browse a webapp page

	Note over r: No session cookie
	r->>p: Initial API request<br/>for the API server

	p->>p: Read the session cookie<br/>and check for user session

	Note over p: No session found<br/>trigger a login

	p->>r: Login HTML page

	r->>b: Change the window.location<br/>to the login page
	Note over b: Browse the login page
	b->>p: The user selects the test user

	p->>b: Change the window.location<br/>to the success URL
	b->>p: Get on the success URL
	Note over p: New session created
  p->>b: Set the session cookie<br/>and redirect to the original webapp page

  Note over b, s: Existing session

  b->>r: Browse the original webapp page

	Note over r: With a session cookie
	r->>p: New API request<br/>for the API server

	p->>p: Read the session cookie<br/>and check for user session

	Note over p: A session found<br/>proxy to the API server

	p->>s: API request<br/>+ encoded user data (JWT, ...)
  Note over s: Read user data (RBAC, ...)
	s->>r: API response