inrupt / inrupt/solid-client-authn-js

No support for IdPs using multiple JWK certificates

Open
#1,799 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
77
Forks
49
Avg merge
18h 20m
Merged PRs (30d)
32

Description

Impacted package

Which packages do you think might be impacted by the bug ?

  • solid-client-authn-browser
  • solid-client-authn-node
  • solid-client-authn-core
  • oidc-client-ext
  • Other (please specify): ...
Bug description

It is not uncommon for OIDC IdPs to use multiple JWK keys, resulting in the array published at jwks_uri to have more than one element. For example:

  • Google has 3 keys (JWKS);
  • Connect2ID has 9 keys (JWKS);
  • Keycloak realms have 3 keys by default;
  • Okta has 2 keys (JWKS);
  • Microsoft has 7 keys (JWKS);
  • Ping deployments can use up to 16 keys (!)

(While Google, MS and Okta are of low relevance here, Ping, Keycloak and Connect2ID could potentially become Solid-OIDC compliant in the near future as they either already ship the necessary features like DPoP and PKCE or will start shipping them soon.)

Currently, this is not supported by the library as it would just pick the first key (IRedirectHandler.ts:73):

 // The JWKS should only contain the current key for the issuer.
  let jwk: JWK;
  try {
    jwk = (await jwksResponse.json()).keys[0] as JWK;
  } catch (e) {
    throw new Error(
      `Malformed JWKS for [${issuerIri}] at [${jwksIri}]: ${
        (e as WithMessage).message
      }`
    );
  }
  return jwk;

The statement about JWKS having to contain only the current key seems erroneous to me; I couldn't find any specification that would mandate the only key. Actually, the kid of the key should be matched against the corresponding header claim of the access/ID token.

@justinwb @jamiefiedler

Expected result

Successful validation of acess/ID tokens minted by an IdP using multiple keys.

Actual result

Validation would only succeed if the token was signed by the first key from the published JWKS set.

Environment
  System:
    OS: Linux 5.10 Mageia 8
    CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 1.80 GB / 15.48 GB
    Container: Yes
    Shell: 5.1.4 - /bin/bash
  Binaries:
    Node: 14.17.6 - /usr/bin/node
    npm: 6.14.15 - /usr/bin/npm
  Browsers:
    Chrome: 95.0.4638.69
    Firefox: 91.3.0esr
  npmPackages:
    @babel/core: ^7.12.16 => 7.12.16 
    @babel/plugin-proposal-class-properties: ^7.12.13 => 7.12.13 
    @babel/preset-react: ^7.12.13 => 7.12.13 
    @datapunt/matomo-tracker-react: ^0.3.1 => 0.3.1 
    @date-io/date-fns: ^1.3.13 => 1.3.13 
    @inrupt/eslint-config-base: ^0.0.4 => 0.0.4 
    @inrupt/eslint-config-react: ^0.0.4 => 0.0.4 
    @inrupt/prism-react-components: ^0.13.7 => 0.13.7 
    @inrupt/solid-client: ^1.15.0 => 1.15.0 
    @inrupt/solid-client-access-grants: ^0.3.3-fix2258-verification-endpoint-discovery-1412767200-263-1635864188.0 => 0.3.3-fix2258-verification-endpoint-discovery-1412767200-263-1635864188.0 
    @inrupt/solid-client-authn-browser: ^1.8.2 => 1.8.2 
    @inrupt/solid-ui-react: ^2.3.1 => 2.3.1 
    @material-ui/core: ^4.11.3 => 4.11.3 
    @material-ui/icons: ^4.11.2 => 4.11.2 
    @material-ui/lab: ^4.0.0-alpha.57 => 4.0.0-alpha.57 
    @material-ui/pickers: ^3.3.10 => 3.3.10 
    @sentry/node: ^6.1.0 => 6.1.0 
    @sentry/react: ^6.1.0 => 6.1.0 
    @sentry/webpack-plugin: ^1.14.0 => 1.14.0 
    @solid/lit-prism-patterns: ^0.13.7 => 0.13.7 
    @solid/lit-prism-theme-sdk-default: ^0.13.7 => 0.13.7 
    @testing-library/dom: ^7.29.4 => 7.29.4 
    @testing-library/jest-dom: ^5.11.9 => 5.11.9 
    @testing-library/react: ^11.2.5 => 11.2.5 
    @testing-library/react-hooks: ^5.1.2 => 5.1.2 
    @testing-library/user-event: ^12.7.1 => 12.7.1 
    @types/jest: ^26.0.20 => 26.0.20 
    @types/react: ^17.0.2 => 17.0.2 
    @types/react-table: ^7.0.28 => 7.0.28 
    @typescript-eslint/eslint-plugin: ^3.10.1 => 3.10.1 
    @typescript-eslint/parser: ^3.10.1 => 3.10.1 
    babel-eslint: ^10.1.0 => 10.1.0 
    babel-jest: ^26.6.3 => 26.6.3 
    date-fns: ^2.23.0 => 2.23.0 
    encoding: ^0.1.13 => 0.1.13 
    eslint: ^7.20.0 => 7.20.0 
    eslint-config-airbnb: ^18.2.0 => 18.2.0 
    eslint-config-airbnb-base: ^14.2.0 => 14.2.0 
    eslint-config-next: ^11.0.1 => 11.0.1 
    eslint-config-prettier: ^6.15.0 => 6.15.0 
    eslint-plugin-babel: ^5.3.1 => 5.3.1 
    eslint-plugin-import: ^2.22.1 => 2.22.1 
    eslint-plugin-jest: ^23.17.1 => 23.20.0 
    eslint-plugin-jsx-a11y: ^6.4.1 => 6.4.1 
    eslint-plugin-license-header: ^0.2.0 => 0.2.0 
    eslint-plugin-prettier: ^3.1.4 => 3.1.4 
    eslint-plugin-react: ^7.21.5 => 7.21.5 
    eslint-plugin-react-hooks: ^4.2.0 => 4.2.0 
    http-link-header: ^1.0.3 => 1.0.3 
    husky: ^4.3.7 => 4.3.7 
    jest: ^26.6.3 => 26.6.3 
    jest-localstorage-mock: ^2.4.3 => 2.4.3 
    jest-mock-extended: ^1.0.10 => 1.0.10 
    jest-raw-loader: ^1.0.1 => 1.0.1 
    jsdom: ^16.4.0 => 16.4.0 
    jsdom-global: 3.0.2 => 3.0.2 
    jss: ^10.5.1 => 10.5.1 
    jss-preset-default: ^10.5.1 => 10.5.1 
    license-checker: ^25.0.1 => 25.0.1 
    next: ^11.0.1 => 11.0.1 
    next-runtime-dotenv: ^1.4.0 => 1.4.0 
    nock: ^13.1.1 => 13.1.1 
    node-mocks-http: ^1.10.1 => 1.10.1 
    prettier: ^2.2.1 => 2.2.1 
    prop-types: ^15.7.2 => 15.7.2 
    raw-loader: ^4.0.2 => 4.0.2 
    rdf-namespaces: ^1.9.2 => 1.9.2 
    react: ^17.0.2 => 17.0.2 
    react-dom: ^17.0.2 => 17.0.2 
    react-id-generator: ^3.0.1 => 3.0.1 
    react-jss: ^10.4.0 => 10.4.0 
    react-table: ^7.6.3 => 7.6.3 
    react-test-renderer: ^17.0.1 => 17.0.1 
    react-transition-group: ^4.4.1 => 4.4.1 
    swr: ^0.4.2 => 0.4.2 
    typescript: ^4.4.3 => 4.4.3 
    uuid: ^8.3.1 => 8.3.1 
    vercel: ^21.2.3 => 21.2.3 
    whatwg-fetch: ^3.5.0 => 3.5.0 
  npmGlobalPackages:
    npm: 6.14.15

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at packages/core/src/login/oidc/redirectHandler/IRedirectHandler.ts around line 73, where the JWKS response currently selects the first key, and inspect how the token header identifies its key. Done means access and ID tokens signed by any matching key in a multi-key JWKS can be validated rather than only tokens signed by the first key.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
authentication, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.