Skip to content

Conversation

@JeanLuX
Copy link

@JeanLuX JeanLuX commented Oct 31, 2025

Summary of change

Modifications to Support Android Native WebAuthn Origins

Context

Currently, when attempting to define an Android Native origin (in the format android:apk-key-hash:<base64Url-string-without-padding-of-fingerprint>) through supertokens_python.recipe.webauthn.register_options and supertokens_python.recipe.webauthn.sign_in_options, the Core returns an INVALID_OPTIONS_ERROR status without specifying a reason. The "origin" field of these functions appears to only work with HTTP(S) URLs.

There is no indication of this limitation in any of the documentation I've reviewed, which leads me to believe this has never been tested under these conditions (i.e., from an Android Native application, without an Pre-Built UI (frontend SDK), as is possible with react-native-passkey).

I initially attempted to use Function overrides, a solution I'm not particularly fond of. While this can work during the "Register Options" phase (where it's possible to switch the Android Native origin to the HTTPS URL provided as the origin when calling the Python function to bypass the Core), it becomes impossible during the Sign-In phase, as this invalidates the signature sent by the device, causing the Core to legitimately reject the request.

Therefore, I propose this PR with several modifications to allow the Core to support this origin format in the same way it handles HTTP(S) URLs, avoiding these workarounds (which don't work anyway).

This is my first pull request to an open source project of this scale, and I'm open to any feedback if I'm on the wrong track or doing things incorrectly.

Modified Files

1. OptionsValidator.java

File: src/main/java/io/supertokens/webauthn/validator/OptionsValidator.java

Changelog:

  • Added detection for Android origins starting with android:apk-key-hash:
  • Strict validation of the URL-safe base64 hash:
    • Verification that the hash is not empty
    • Validation of URL-safe base64 format (allowed characters: A-Z, a-z, 0-9, -, _)
    • Verification of exact length: 43 characters (base64 of SHA-256 fingerprint, 32 bytes)
  • HTTP(S) origins continue to work normally

2. Utils.java (Tests)

File: src/test/java/io/supertokens/test/webauthn/Utils.java

Modifications:

  • Added overloads for registerOptions() and signInOptions() accepting an origin parameter
  • Allows easy testing with different types of origins

3. TestAndroidOriginValidation.java (New File)

File: src/test/java/io/supertokens/test/webauthn/api/TestAndroidOriginValidation.java

Tests Added:

  1. testValidAndroidOrigin() : Verifies that a valid Android origin is accepted
  2. testValidAndroidOriginWithAlternativeHash() : Tests with an alternative valid hash
  3. testAndroidOriginWithEmptyHash() : Verifies rejection of an empty hash
  4. testAndroidOriginWithInvalidCharacters() : Verifies rejection of invalid characters
  5. testAndroidOriginWithInvalidLength() : Verifies rejection of incorrect length (must be exactly 43 characters)
  6. testAndroidOriginForSignInOptions() : Tests Android origins for sign-in
  7. testMixedOriginsSupport() : Verifies that HTTP, HTTPS, and Android coexist

Test Execution

I executed this test to validate proper functionality:

From the supertokens-root:

./gradlew :supertokens-core:test --tests "io.supertokens.test.webauthn.api.TestAndroidOriginValidation"
image

Origin Examples

Valid Android Origins

android:apk-key-hash:47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
android:apk-key-hash:sYUC8p5I9SxqFernBPHmDxz_YVZXmVJdW8s-m3RTTqE
android:apk-key-hash:AbCdEfGhIjKlMnOpQrStUvWxYz0123456789-_AbCd

Invalid Android Origins

android:apk-key-hash:                                  # Empty hash
android:apk-key-hash:invalid@hash#with$special!        # Invalid characters (not URL-safe base64)
android:apk-key-hash:abc                               # Incorrect length (must be 43 characters)
android:apk-key-hash:Lir5oIjf552K/XN4bTul0VS2aiE=      # Incorrect length and contains invalid characters (+/ and =)

HTTP(S) Origins (Still Supported)

http://example.com
https://example.com
https://subdomain.example.com

WebAuthn Specification Compliance

These modifications comply with the WebAuthn specification, which defines different origin formats depending on the platform:

Security Notes

  • The URL-safe base64 hash (43 characters) represents the SHA-256 fingerprint of the Android application's signing certificate
  • This validation ensures that only legitimate Android applications with the correct certificate can use WebAuthn
  • Android origins are not validated against the relyingPartyId in the same way as HTTP(S) origins (compliant with the spec)
  • The hash format follows the WebAuthn specification for Android native applications

Test Plan

Command used to test the implementation:

gradle test --tests "io.supertokens.test.webauthn.api.TestAndroidOriginValidation"

Documentation changes

I don't feel it's necessary to make changes to the documentation, as there was nothing to suggest the current limitation. This should be transparent to the few people in this situation.

Checklist for important updates

  • Changelog has been updated
    • If there are any db schema changes, mention those changes clearly
  • coreDriverInterfaceSupported.json file has been updated (if needed)
  • pluginInterfaceSupported.json file has been updated (if needed)
  • Changes to the version if needed
    • In build.gradle
  • If added a new paid feature, edit the getPaidFeatureStats function in FeatureFlag.java file
  • Had installed and ran the pre-commit hook
  • If there are new dependencies that have been added in build.gradle, please make sure to add them
    in implementationDependencies.json.
  • Update function getValidFields in io/supertokens/config/CoreConfig.java if new aliases were added for any core
    config (similar to the access_token_signing_key_update_interval config alias).
  • Issue this PR against the latest non released version branch.
    • To know which one it is, run find the latest released tag (git tag) in the format vX.Y.Z, and then find the
      latest branch (git branch --all) whose X.Y is greater than the latest released tag.
    • If no such branch exists, then create one from the latest released branch.
  • If added a foreign key constraint on app_id_to_user_id table, make sure to delete from this table when deleting
    the user as well if deleteUserIdMappingToo is false.
  • If added a new recipe, then make sure to update the bulk import API to include the new recipe.

@JeanLuX JeanLuX force-pushed the feat/WebAuthn-Support-Android-Native-Origin branch 3 times, most recently from 7559e89 to 7504841 Compare November 1, 2025 12:40
@JeanLuX JeanLuX marked this pull request as ready for review November 1, 2025 12:46
following the format: android:apk-key-hash:<base64Url-string-without-padding-of-fingerprint>
@JeanLuX JeanLuX force-pushed the feat/WebAuthn-Support-Android-Native-Origin branch from 7504841 to 8f2f86e Compare November 1, 2025 12:49
@JeanLuX JeanLuX changed the title feat(webauthn): allow native Android origins feat(webauthn): allow Android native origin Nov 1, 2025
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.

1 participant