-
public final class OAuthHandlerManages OAuth authentication flows using Chrome Custom Tabs.
zerohash uses a confidential-client OAuth architecture: the authorization code → token exchange happens entirely server-side inside connection-service, which holds the
client_secret. The Android SDK never sees the raw authorization code; connection-service validates the OAuth callback, performs the token exchange, and then redirects to the web app's oauth-callback page which in turn firesconnectsdk-oauth://callback?connectionId=<uuid>.PKCE (RFC 7636) is designed for public clients that perform the token exchange on-device (e.g., a native app calling the token endpoint directly). It protects against an intercepted authorization code being exchanged by a third party. Here the token exchange is handled server-side by connection-service using
client_secret— a stronger form of client authentication. Adding acode_challengefrom the SDK without a matchingcode_verifierfrom connection-service would break the token exchange if the OAuth provider enforces PKCE when the parameter is present. Additionally, the OAuth authorization URL is already constructed by connection-service, which appends its ownstatetoken; prepending anotherstatefrom the SDK creates a duplicate parameter that breaks connection-service's own CSRF protection.CSRF protection via
stateis already implemented server-side: connection-service generates a 256-bit randomstatetoken (GenerateState()inutils.go), stores it against the pending connection in MongoDB, and verifies it when the OAuth provider redirects back. The final redirect toconnectsdk-oauth://callbackonly carriesconnectionId— thestateis fully consumed by the backend and never forwarded to the SDK. Validating astatethat is never present in the callback would unconditionally reject every OAuth response.The primary mitigation for custom-scheme hijacking is that the callback only delivers a
connectionId(not an authorization code or tokens). Connection-service has already completed the token exchange before this callback fires. A malicious app that intercepts the intent receives only a reference UUID; it cannot exchange that for credentials without proper authentication against the zerohash API.Additional defense in depth from the post-merge review:
The exported intent-filter lives on OAuthCallbackActivity, not on xyz.connect.sdk.ui.WebViewActivity, so the JWT-bearing activity is not reachable from external apps.
This handler validates that
connectionIdis a well-formed UUID before forwarding it — a malicious app firing the intent cannot inject arbitrary strings.Provider-supplied
error_descriptionis sanitised to the RFC 6749 §5.2 error-code allowlist before being surfaced to integrators.
F-007: OAuth URLs and connection IDs are only logged in debug builds.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description public classOAuthHandler.Companionpublic interfaceOAuthHandler.OAuthCallback
-
Constructor Summary
Constructors Constructor Description OAuthHandler(Activity activity)
-
Method Summary
Modifier and Type Method Description final UnitstartOAuthFlow(String url, OAuthHandler.OAuthCallback callback)Start OAuth flow with Chrome Custom Tabs. final BooleanhandleCallback(Intent intent)Handle OAuth callback from redirect. final Unitclear()Clear current state (e.g., on activity destroy). -
-
Constructor Detail
-
OAuthHandler
OAuthHandler(Activity activity)
-
-
Method Detail
-
startOAuthFlow
final Unit startOAuthFlow(String url, OAuthHandler.OAuthCallback callback)
Start OAuth flow with Chrome Custom Tabs.
The authorization URL is passed through unchanged — connection-service has already appended the
statetoken and any other required parameters to the URL before the web app forwarded it to the SDK via thenavigatemessage.- Parameters:
url- OAuth authorization URL constructed by connection-servicecallback- Callback for OAuth results
-
handleCallback
final Boolean handleCallback(Intent intent)
Handle OAuth callback from redirect.
Validates scheme and host of the incoming intent, then extracts the
connectionIdfrom query parameters or fragment. Rejects non-UUID connectionIds (F-003 review) and sanitises provider-supplied errors to standard OAuth 2.0 codes (F-013 review).- Parameters:
intent- Intent containing the callback URL
-
-
-
-