Repository navigation
BFF: baseUrl is the backend, and permissions come from the session - #49
Merged
brionmario merged 1 commit intoOct 30, 2026
Merged
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
🔀 Cross-SDK feature parity, ports raisedThis pull request is labelled Ports (DO NOT EDIT)
3 of 3 sibling SDKs accounted for. Every sibling SDK is accounted for. The contract is in the SDK development specification. |
8 of 13 tasks
Member
Author
|
…ession In backend mode the config's baseUrl is now the backend (the BFF). A relative backend endpoint resolves against it, and an absolute HTTPS URL is used as is. The API whose requests go through the backend's proxy is endpoints.backend.apiBaseUrl, which defaults to baseUrl. endpoints.backend.baseUrl is gone. baseUrl, the API base, absolute endpoints and bypass URLs must use HTTPS. The SDK's own API calls in backend mode (the /users/me profile and the management APIs) go to the API base, through the proxy. Redirect mode is unchanged. getGrantedPermissions() used to decode the access token, which in backend mode meant asking the backend's token endpoint for one; a BFF doesn't offer that, so the app saw no permissions. BackendSession now carries the granted scopes (scope, the token response's scope), and in backend mode getGrantedPermissions() reads them from the session. A session without scope grants nothing, and the SDK never asks for a token. In redirect mode it still reads the access token. The README documents backend mode, and the playground uses the backend URL as baseUrl with the ThunderID server as the API base. Signed-off-by: Brion <info@brionmario.com>
brionmario
force-pushed
the
granted-scopes-backend-session
branch
from
October 30, 2026 08:47
554a5a4 to
67e5828
Compare
6 of 13 tasks
DonOmalVindula
approved these changes
Oct 30, 2026
Merged
6 of 13 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
Two changes to backend mode (
endpoints.backend), where a backend the app owns runs sign-in and keeps the tokens (the BFF pattern of RFC 10017).baseUrlis the backend. The backend's own address used to beendpoints.backend.baseUrl, while the top-levelbaseUrlwas the API behind the proxy. Now the top-levelbaseUrlis the backend, and backend endpoints resolve against it, like the server's address in redirect mode. API requests go to the backend'sproxy, which maps them to the API from its own configuration, so the app never needs the API's address: the SDK's own calls go to{baseUrl}{proxy}/users/me,{baseUrl}{proxy}/groupsand so on.Permissions come from the session.
ThunderIDClient.getGrantedPermissions()read the permissions by decoding the access token. In backend modegetAccessToken()asks the backend's token endpoint for one, which a BFF doesn't offer, since keeping tokens away from the app is the point of the pattern (RFC 10017 §6.1). The app then saw no permissions, and Compose'srememberGrantedPermissions()hid everything. An OAuth client learns what it was granted from the token response'sscope(RFC 6749 §5.1), so the backend reports it with the session, and the SDK reads it from there.Approach
baseUrlis the backend and must use HTTPS.endpoints.backend.baseUrlis removed./) resolves againstbaseUrl, and an absolute HTTPS URL is used as is. Anything else, including anhttpURL, is refused atinitialize(). Unset endpoints still default to paths under/api/auth./users/meprofile calls and the management APIs (collections and administration flows) are built on the resolved proxy,{baseUrl}{proxy}/…. Collection overrides inendpointsstill win.httpRequest: a relative path is sent under the proxy, and a URL already under the proxy is sent as is, never prefixed twice. A bypass URL goes straight there, as before. Any other absolute URL is refused without being sent.BackendSessiongains an optionalscope, the granted scopes as space-separated text, parsed from the backend's session response.getGrantedPermissions()reads only the session'sscope. It never asks for the access token, and a session withoutscopegrants nothing. Redirect mode is unchanged throughout.THUNDERID_BACKEND_URLasbaseUrland calls/users/merelative to the proxy.This is the Android port of thunder-id/javascript-sdks#148 (permissions from the session) and #149 (
baseUrlis the backend). In #149 JavaScript also added anendpoints.backend.apiBaseUrl; this port doesn't, and thunder-id/javascript-sdks#150 removes it from JavaScript.Related Issues
Related PRs
baseUrlconfig as the BFF's base URL javascript-sdks#149: the original changes.apiBaseUrl.Checklist
BackendEndpointsTest: endpoints resolve againstbaseUrl, absolute HTTPS endpoints used as is, non-HTTPSbaseUrland endpoints refused.BackendModeTest: the SDK's own calls are built onbaseUrland the configured proxy, a relative path goes under the proxy, a URL already under it isn't prefixed twice, a foreign absolute URL is refused, permissions from the session with no token request, noscopegrants nothing.)breaking changelabel added.parity/prs-raisedorparity/prs-not-neededadded.parity/prs-raised, the port links are posted as a reply on the parity check's comment.Verified locally with JDK 17:
./gradlew ktlintCheck testDebugUnitTest assembleDebugpasses (336 unit tests, 0 failures), and the playground'scompileDebugKotlinpasses. Android lint (./gradlew lint) was not run.Security checks
Every backend URL must use HTTPS, and the app never holds the API's address. In backend mode the app never asks for an access token to read permissions; the permissions decide only what the app shows, and the server still checks every request.