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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@oslokommune/auth-bff

v2.2.2

Published

A NodeJS Backend for frontend.

Readme

auth-bff

A NodeJS Backend for frontend.

Features:

  • Serves a static web app
  • Proxies API calls, with the user's access token
  • Two "modes" of operation
    • A vite plugin for use during development
    • A standalone mode for use in production (e.g. inside a docker container)
  • Supports generic OIDC auth code flow clients
  • Has special support for okdata-generated Idporten clients
  • Handles login/logout and sessions (using DynamoDb as a store)
  • Includes simple React components for handling login-state

See https://github.com/oslokommune/auth-bff-example for an example React app using this package.

Getting started

Dev mode

  1. Install package
npm install @oslokommune/auth-bff
  1. Add plugin to your vite config
import {defineConfig} from 'vite'
import bff from '@oslokommune/auth-bff/vite-plugin'

export default defineConfig({
  plugins: [
    bff()
  ],
  ...
})
  1. Create a config file

  2. Run!

Standalone mode

  1. Install package globally
npm install -g @oslokommune/auth-bff
  1. Create a config file

  2. Run with

auth-bff

Running in Docker

When running in docker you should specify the version to use, and make sure it matches the one used in package.json.

Example dockerfile:

FROM node:24-alpine AS base

FROM base AS build
WORKDIR /home/app
COPY package*.json /home/app
RUN npm ci
COPY . ./
RUN npm run build

FROM base
WORKDIR /application
EXPOSE 8080
COPY --from=build /home/app/dist /application/dist
ENV NODE_ENV=production
RUN npm install -g @oslokommune/auth-bff@<version>
COPY bff.config.json /application/
CMD ["auth-bff"]

To use different configuration for different environments, you can create separate config files for each and select it at build time (using build args). For example, with bff.config.dev.json and bff.config.prod.json:

ARG ENVIRONMENT=''
COPY bff.config.${ENVIRONMENT}.json /application/bff.config.json
CMD ["auth-bff"]

Or select it at runtime, using an env var:

COPY bff.config*.json /application/
CMD exec auth-bff --configFile bff.config.${ENVIRONMENT}.json

Configuration

Configuration is defined in json-files that look like this:

{
  "issuer": "https://example-issuer.com/",
  "clientId": "example-client",
  "clientSecret": "{ssm:/secret/from/parameter/store}",
  "redirectUri": "http://localhost:3000/auth/callback",
  "cookieSecure": false,
  "cookieSameSite": false,
  "postLogoutRedirectUri": "http://localhost:3000/",
  "sessionSecret": "{env:SECRET_FROM_ENV}",
  "sessionStoreType": "memory",
  "proxyTargets": {
    "/api": "http://localhost:8080/api"
  }
}

By default it looks for a file named bff.config.json, but this can be overridden:

Vite:

plugins: [
  bff({configFile: ['bff.config.local.json', 'bff.config.json']}) //First existing file is used
]

Standalone:

auth-bff --configFile /path/to/bff.config.json

Loading values from environment or AWS Parameter Store

The config file supports two special forms for loading values from other sources. Primarily meant for loading secrets:

Environment values:

{
  "sessionSecret": "{env:MY_SECRET}"
}

AWS Parameter store:

{
  "sessionSecret": "{ssm:/name/of/parameter}"
}

This loads from the configured AWS environment. For this to work on your local machine the AWS_PROFILE environment variable must be set, and you must be signed in to that profile

[!NOTE]
️ See config.ts for a description of all config parameters

Mixing public and protected routes

If the application has some routes that should be reachable without an authenticated session (e.g. a public catalog or a download endpoint polled by CI), list them under publicProxyTargets:

{
  "proxyTargets": {
    "/api": "http://localhost:8080/api"
  },
  "publicProxyTargets": {
    "/api/public": "http://localhost:8080/api/public",
    "/export.zip": "http://localhost:8080/export.zip"
  }
}

Public targets are proxied through anonymously — no session lookup, no Authorization header. The session cookie is stripped on the way through.

Public targets are registered before protected ones, so overlapping paths resolve to the public mapping (e.g. publicProxyTargets["/api/public"] wins over proxyTargets["/api"]).

Using with ID-porten (via okdata):

auth-bff Has special support for keys generated by okdata.

  1. Start by creating a new client and key using okdata:
~> okdata pubs create-client
* Environment test
* Team <team>
* Client type ID-porten
* Integration name  (identifying in which system or case this client will be used) <your name here>
* Redirect URIs (comma-separated) http://localhost:3000/auth/callback
* Post logout Redirect URIs (comma-separated) http://localhost:3000
* Frontchannel logout URI http://localhost:3000/auth/logout
* Client URI (back URI) http://localhost:3000
...
~> okdata pubs create-key
* Environment test
* Client <same client as above>
* Where should the key be stored? Send the key to your AWS Parameter Store
* AWS account number <accno>
* AWS region eu-west-1 (Ireland)
* Automatic key rotation will replace the key in SSM nightly on weekdays.
  Enable automatic key rotation for this client? Yes
...
A new key has been created and the following parameters have been written to SSM:
- /okdata/maskinporten/11111111-2222-3333-4444-555555555555/key.json
...
  1. Set the following options in the config file:
{
  "issuer": "https://test.idporten.no/",
  "clientId": "11111111-2222-3333-4444-555555555555",
  "okDataIdPortenKeyName": "/okdata/maskinporten/11111111-2222-3333-4444-555555555555/key.json",
  ...
}

Note that when using okDataIdPortenKeyName, that key is used for authentication, and clientSecret is not used. Also, since the key is fetched from Parameter Store, you must set AWS_PROFILE and be signed in to that profile when running locally.

  1. Done!

Using with Entra ID:

When using the package with Entra ID, you need to get credentials from Azure. You need to collect following credentials in order to be able to use this package:

  • issuer
  • client id
  • client secret

With Entra ID you need to make sure to remove "okDataIdPortenKeyName"from the configuration file and replace it with client secret.

{
  "issuer": "https://login.microsoftonline.com/{TENANT_ID}/v2.0",
  "clientId": "1111111q-2bab-3333-c444-5555e556cb55",
  "clientSecret": "7dW3Q~_sdfj3-4f5g-6789-h0i1-2j3k4l5m6n7",
  ...
}

Configuring session storage

Currently only dynamoDb is supported for storing sessions in production. It requires some setup. To work properly, the table must have ttl enabled, and an extra index for the idp-sid-property (used to delete sessions during front-channel logout)

[!WARNING]
If the table does not exist, it will be automatically created with settings not appropriate for production.

Here is an example configuration in terraform. If you are using Golden Path, you can simply copy this to a file in your application stack, and run terraform apply

resource "aws_dynamodb_table" "session_dynamodb_table" {
  name         = "${local.environment}-${local.main_container_name}-sessions"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "id"

  on_demand_throughput {
    max_read_request_units  = 20
    max_write_request_units = 20
  }

  attribute {
    name = "id"
    type = "S"
  }

  attribute {
    name = "idp-sid"
    type = "S"
  }

  ttl {
    enabled        = true
    attribute_name = "expires"
  }

  global_secondary_index {
    hash_key        = "idp-sid"
    name            = "idp-sid-index"
    projection_type = "KEYS_ONLY"
    on_demand_throughput {
      max_read_request_units  = 20
      max_write_request_units = 20
    }
  }
}

Then remember to update the config to use the new table:

{
  "sessionStoreOptions": {
    "table": "myteam-dev-myservice-sessions"
  }
}

The read/write limits above are just an example, and can be changed/removed

Required AWS permissions

When using SSM parameters or okDataIdPortenKeyName in the config, the service will need the ssm:GetParameter permission for each parameter

If using dynamodb, the service will need the following permissions for the table

dynamodb:CreateTable
dynamodb:DescribeTable
dynamodb:PutItem
dynamodb:DeleteItem
dynamodb:GetItem
dynamodb:Scan
dynamodb:UpdateItem

React component

This package also includes a React component for handling authentication state. It will redirect to login if required and optionally automatically poll for changes to authentication state.

AuthContextProvider

import {AuthContextProvider} from "@oslokommune/auth-bff/react";
import {PktLoader} from "@oslokommune/punkt-react";

const fiveMinutes = 5 * 60 * 1000;

<AuthContextProvider authRequired={true} loaderComponent={<PktLoader/>} pollInterval={fiveMinues}>
  <App/>
</AuthContextProvider>

| Option | Description | |-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| | authRequired | Whether authentication is required. If true, will redirect to login before rendering child components (default: true) | | loaderComponent | React component to display while loading auth state. (default: null) | | baseUrl | Must be set to the same baseUrl as in the json config for login/logout to work correctly (default: '') | | pollInterval | Minimum interval in milliseconds between checks if session is still active. Will set authState to 'expired' if session is expired (default: disabled) |

useAuthContext

Hook to get current AuthState. Must be called in a component inside the AuthContextProvider.

import {useAuthContext} from "@oslokommune/auth-bff/react";

const {user, authState, login} = useAuthContext()
if (authState === 'authenticated') {
  console.log(`Hello, ${user.pid}`)
} else {
  login()
}

| Property | Description | |-----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------| | user | The currently logged in user, or null if not logged in. User object contains the id_token claims returned from the usr endpoint. See config option userClaims. | | login | Function that will redirect to the login endpoint when invoked | | logout | Function that will redirect to the logout endpoint when invoked | | authState | Current auth state. See table below for values | | |

AuthState

| Value | Description | |-----------------|------------------------------------------------------------------------------------------------------------------| | pending | Initial value before auth state has been determined | | authenticated | User is authenticated. | | unauthenticated | User is not authenticated | | expired | User was authenticated, but the session has expired. Can be used to display message to user or redirect to login | | | | error | Failed to determine auth state | | |

Content Security Policy

To configure the content security policy returned by the server, use the contentSecurityPolicy config option. This configuration is passed almost as-is to helmet. Note that since our configuration is json only, not all features are supported.

Nonce

To set a nonce, use the special form "{nonce}". It will be replaced by a generated nonce for each request. For example:

{
  "contentSecurityPolicy": {
    "directives": {
      ...
      "script-src": ["'self'", "{nonce}", ...]
    }
  }
}

To use a nonce in your app, use __CSP_NONCE__ in your html. It will be replaced with a nonce for each request:

<script nonce="__CSP_NONCE__">
    ...
</script>

Inject config

If your application requires configuration that needs to be determined at runtime, you can use injectConfig to inject these values into a served html file:

{
  "injectConfig": {
    "enableSomeFeature": true,
    "publicToken": "{env:MY_PUBLIC_TOKEN}"
  }
}

Then add something this to your index.html:

<script nonce="__CSP_NONCE__">
    const injectedConfig = __INJECTED_CONFIG__
</script>

When rendered, __INJECTED_CONFIG__ will be replaced with the values from injectConfig:

<script nonce="abcdef123456">
    const injectedConfig = {
        "enableSomeFeature": true,
        "publicToken": "pub123abc"
    }
</script>

[!WARNING]
Do not put any secrets or other sensitive values in the injected config, they will be publicly visible.