Skip to content

Verify the launching browser's signature with LAUNCHING_BROWSER_TOKEN - #639

Merged
dtonderski-google merged 3 commits into
GoogleChrome:mainfrom
dtonderski-google:main
Oct 12, 2026
Merged

dtonderski-google merged 3 commits into
GoogleChrome:mainfrom
dtonderski-google:main

Conversation

@dtonderski-google

Copy link
Copy Markdown
Collaborator

LAUNCHING_BROWSER pins a TWA to a browser by package name only, so any app installed under that name is trusted. The new LAUNCHING_BROWSER_TOKEN metadata also pins the browser's signing certificate: it holds a base64-encoded androidx.browser.trusted.Token, and the TWA is only launched if the installed LAUNCHING_BROWSER package matches it (signing key rotation is supported on API 28+).

If verification fails (browser missing or mismatched, invalid token, or token set without LAUNCHING_BROWSER), the launch fails closed:

  • the browser is not bound to or launched, and the fallback strategy is given a null provider package;
  • LauncherActivity shows the "browser unavailable" dialog, even if a WebView fallback is configured, and ShortcutTrampolineActivity drops the launch;
  • the browser is not remembered as the last launched provider, and the stored delegation Token is cleared (except on ChromeOS).

TwaLauncher gets a constructor that takes the expected Token, for apps that use it directly. On a mismatch, CCT_FALLBACK_STRATEGY is replaced by the blocked dialog, as it could otherwise open the URL in the unverified browser.

Behaviour is unchanged when LAUNCHING_BROWSER_TOKEN is not set.

LAUNCHING_BROWSER pins a TWA to a browser by package name only, so any
app installed under that name is trusted. The new LAUNCHING_BROWSER_TOKEN
metadata also pins the browser's signing certificate: it holds a
base64-encoded androidx.browser.trusted.Token, and the TWA is only
launched if the installed LAUNCHING_BROWSER package matches it (signing
key rotation is supported on API 28+).

If verification fails (browser missing or mismatched, invalid token, or
token set without LAUNCHING_BROWSER), the launch fails closed:
- the browser is not bound to or launched, and the fallback strategy is
  given a null provider package;
- LauncherActivity shows the "browser unavailable" dialog, even if a
  WebView fallback is configured, and ShortcutTrampolineActivity drops
  the launch;
- the browser is not remembered as the last launched provider, and the
  stored delegation Token is cleared (except on ChromeOS).

TwaLauncher gets a constructor that takes the expected Token, for apps
that use it directly. On a mismatch, CCT_FALLBACK_STRATEGY is replaced by
the blocked dialog, as it could otherwise open the URL in the unverified
browser.

Behaviour is unchanged when LAUNCHING_BROWSER_TOKEN is not set.

@gstepniewski-google gstepniewski-google left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also update CHANGELOG.md

Comment thread README.md Outdated
Comment thread README.md Outdated
- Log distinct messages in ShortcutTrampolineActivity's fallback for a
  missing browser, a browser that failed token verification, and a token
  set without LAUNCHING_BROWSER.
- Test ShortcutTrampolineActivity's handling of LAUNCHING_BROWSER_TOKEN.
- README: generate the token with adb and apksigner instead of from an
  app; update the TwaLauncher constructor arity.
- Add a CHANGELOG entry.
@gstepniewski-google

Copy link
Copy Markdown
Collaborator

make sure to squash before merging

@dtonderski-google
dtonderski-google merged commit 05f859f into GoogleChrome:main Oct 12, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants