Skip to content

BFF: Treat baseUrl config as the BFF's base URL - #149

Merged
brionmario merged 1 commit into
thunder-id:mainfrom
brionmario:bff-baseurl-backend
Oct 30, 2026
Merged

brionmario merged 1 commit into
thunder-id:mainfrom
brionmario:bff-baseurl-backend

Conversation

@brionmario

Copy link
Copy Markdown
Member

Purpose

In backend mode (endpoints.backend) every backend endpoint had to be spelled out on its own, and the top-level baseUrl meant the API behind the proxy, so pointing an app at its backend for frontend (BFF) took several settings and read the wrong way round. Now baseUrl is the BFF, and the endpoints are resolved against it.

Approach

  • In backend mode the top-level baseUrl is the backend. It's optional and defaults to the page's origin.
  • Each endpoint in endpoints.backend (signIn, session, checkSession, refresh, signOut, proxy, token) given as a path is resolved against baseUrl; an absolute URL is used as it is. The defaults stay /api/auth/..., so they resolve under baseUrl. Without baseUrl the paths stay relative to the page.
  • New endpoints.backend.apiBaseUrl: the API behind the proxy. Requests under it go through proxy. It defaults to baseUrl, then the page's origin.
  • resolveApiBaseUrl(config) gives the base the SDK builds its own API requests on: apiBaseUrl in backend mode (falling back to baseUrl), baseUrl otherwise. It's used by:
    • ThunderIDBrowserClient.getUserProfile() (/users/me);
    • ThunderIDVueClient.getUser() and getUserProfile();
    • the React and Vue providers, for the baseUrl they put in their context, which the account and management components and hooks build their URLs on, and for the organization path. The client itself is still initialized with the real baseUrl.
  • Backend requests send cookies with credentials: 'include', so a BFF on another origin works when its CORS allows credentials. RFC 10017 recommends the app's own origin, and the doc comments say so.
  • OIDC discovery is skipped in backend mode unless endpoints.wellKnown is set: the backend runs OAuth, so there's nothing to discover at baseUrl.
  • Next.js and Nuxt are unchanged: they don't use endpoints.backend.

Related Issues

  • N/A

Related PRs

SDK parity

The mobile SDKs get the same change: in backend mode the top-level baseUrl is the backend, with the API under endpoints.backend.apiBaseUrl.

Checklist

  • Followed the contribution guidelines.
  • Manual test round performed and verified.
  • Documentation provided. (Add links if there are any)
    • The BackendEndpoints, apiBaseUrl and resolveApiBaseUrl doc comments describe the change; no Markdown docs cover backend mode.
  • Tests provided. (Add links if there are any)
    • Unit Tests (resolveBackendEndpoints.test.ts, BackendClient.test.ts, ThunderIDBrowserClient.backend.test.ts, ThunderIDProvider.test.tsx)
    • Integration Tests
  • Breaking changes. (Fill if applicable)
    • Breaking changes section filled.
    • breaking change label added.
  • Cross-SDK parity. Exactly one of parity/prs-raised or parity/prs-not-needed added.
    • If parity/prs-raised, the port links are posted as a reply on the parity check's comment.

Security checks

  • Followed secure coding standards.
  • Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets.

In backend mode (endpoints.backend) the top-level baseUrl is now the
backend, the BFF. It defaults to the page's origin. Every endpoint in
endpoints.backend given as a path is resolved against it, and an
absolute URL is used as it is, so pointing an app at a BFF is one
setting.

The API behind the proxy moves to the new endpoints.backend.apiBaseUrl,
which defaults to baseUrl. Requests under it are sent through the
proxy, and the SDK builds its own API requests on it
(resolveApiBaseUrl). That covers the browser client's and the Vue
client's /users/me, and the baseUrl the React and Vue providers put in
their context, which the account and management components and hooks
build their URLs on. The client itself is still initialized with the
real baseUrl.

Backend requests send cookies with credentials 'include', so a BFF on
another origin works when its CORS allows it, though RFC 10017
recommends the app's own origin. OIDC discovery is skipped in backend
mode unless endpoints.wellKnown is set, since the backend runs OAuth
itself.

Signed-off-by: Brion <info@brionmario.com>
@brionmario brionmario added the parity/prs-raised Ports exist in the other SDKs, or are recorded as not applying there label Oct 30, 2026
@coderabbitai

coderabbitai Bot commented Oct 30, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

🔀 Cross-SDK feature parity, ports raised

This pull request is labelled parity/prs-raised, so the capability it introduces is expected in the other ThunderID SDKs as well.

Ports (DO NOT EDIT)

  • thunder-id/ios-sdks, iOS => #41
  • thunder-id/android-sdks, Android => #49
  • thunder-id/flutter-sdks, Flutter => #62

3 of 3 sibling SDKs accounted for.

Every sibling SDK is accounted for.

The contract is in the SDK development specification.

@brionmario
brionmario merged commit f4d2803 into thunder-id:main Oct 30, 2026
7 of 8 checks passed
@brionmario brionmario changed the title BFF: baseUrl is the backend BFF: Treat baseUrl config as the BFF's base URL Oct 30, 2026
brionmario added a commit to brionmario/thunderid that referenced this pull request Oct 30, 2026
Moves @thunderid/react to 1.11.2 and @thunderid/react-router to 1.10.2,
which bring @thunderid/browser 1.9.2 and @thunderid/javascript 1.10.2.

They include two backend-mode (endpoints.backend) changes:

- thunder-id/javascript-sdks#148: useGrantedPermissions reads the
  granted permissions from the backend's session (scope) instead of
  decoding an access token. A console signed in through a backend (BFF)
  then shows the pages its permissions allow, instead of "Nothing to
  manage".
- thunder-id/javascript-sdks#149: the top-level baseUrl is the backend,
  endpoint paths resolve against it, and the API behind the proxy is
  endpoints.backend.apiBaseUrl.

Neither changes redirect mode, which the consoles use by default.

Signed-off-by: Brion <info@brionmario.com>
brionmario added a commit to brionmario/thunderid that referenced this pull request Oct 30, 2026
Moves @thunderid/react to 1.11.3 and @thunderid/react-router to 1.10.3,
which bring @thunderid/browser 1.9.3 and @thunderid/javascript 1.10.3.

They include three backend-mode (endpoints.backend) changes:

- thunder-id/javascript-sdks#148: useGrantedPermissions reads the
  granted permissions from the backend's session (scope) instead of
  decoding an access token. A console signed in through a backend (BFF)
  then shows the pages its permissions allow, instead of "Nothing to
  manage".
- thunder-id/javascript-sdks#149: the top-level baseUrl is the backend,
  and endpoint paths resolve against it.
- thunder-id/javascript-sdks#150: the SDK's API calls go to the
  backend's proxy (baseUrl + proxy), so the frontend never needs the
  API's own address; the backend maps the proxy to it.

None of them changes redirect mode, which the consoles use by default.

Signed-off-by: Brion <info@brionmario.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parity/prs-raised Ports exist in the other SDKs, or are recorded as not applying there

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants