Skip to content

Android — native (Kotlin + AppAuth-Android) ​

Use a public client with PKCE. Drive the flow with AppAuth-Android.

Pick your path: Follow the guide below, or jump to the AI prompt.

Follow the guide ​

A — Login vs enrol ​

  • Login: build the AuthorizationRequest as usual → /authorize.
  • Enrol: add prompt=create via AuthorizationRequest.Builder.setAdditionalParameters(mapOf("prompt" to "create")) → /authorize?prompt=create.

Choose one of:

  • Option 1 (recommended): "Sign in" and "Create account" buttons, the latter setting prompt=create.
  • Option 2: attempt login; if the result carries error=access_denied + error_description=user_not_registered, retry with prompt=create.

B — Redirect callback setup ​

  • Use Chrome Custom Tabs (AppAuth uses them automatically). Do not use a WebView.
  • Use a custom URL scheme. EntryIdP does not host assetlinks.json, so App Links are not available.
  • Add an <intent-filter> with your android:scheme to the redirect activity in AndroidManifest.xml. The redirect URI (e.g. com.yourapp://callback) must exactly match the registered value.

C — Secure token storage ​

TokenWhere
Access tokenEncryptedSharedPreferences backed by the Android Keystore.
Refresh tokenSame store (persist AppAuth's serialized AuthState).

Use an AI prompt ​

Add EntryIdP biometric OIDC login to this native Android app (Kotlin) using AppAuth-Android.

EntryIdP is an OpenID Connect provider. Users authenticate ONLY with a face liveness
check — no typed credentials, OTPs, or social logins. Do not build any sign-in form or
credential-entry UI.
Issuer: https://idp-test.entryidp.com (use the issuer from my client registration; read
from config — never hardcode in logic).

Before writing code:
1. Add net.openid:appauth to build.gradle if missing. Also add inside defaultConfig:
     manifestPlaceholders["appAuthRedirectScheme"] = "<your-custom-scheme>"
   This is required — AppAuth's bundled manifest uses this placeholder and the Gradle
   manifest merger will fail without it.
2. Open AndroidManifest.xml and declare net.openid.appauth.RedirectUriReceiverActivity
   with tools:node="merge" and an <intent-filter> for your custom scheme.

Implementation:
- Authorization Code + PKCE only. Never implicit flow or response_type=token.
- PUBLIC client: no client_secret anywhere. Use NoClientAuthentication.INSTANCE when
  calling performTokenRequest.
- PKCE: AppAuth does NOT add PKCE automatically. Call
  setCodeVerifier(CodeVerifierUtil.generateRandomCodeVerifier()) on the request builder
  (S256 challenge is derived from the verifier automatically).
- Discovery: use AuthorizationServiceConfiguration.fetchFromIssuer(Uri.parse(issuer)) and
  build the request from the config it hands back. EntryIdP's discovery document carries
  all six fields AppAuth treats as mandatory (issuer, authorization_endpoint, jwks_uri,
  response_types_supported, subject_types_supported,
  id_token_signing_alg_values_supported), so this succeeds — do not hardcode endpoints.
  Only if you are pinned to an old AppAuth release and actually hit
  MissingArgumentException, fall back to fetching
  {issuer}/.well-known/openid-configuration yourself on a background thread and
  constructing AuthorizationServiceConfiguration(authEndpointUri, tokenEndpointUri).
- Use Chrome Custom Tabs (AppAuth default). Do NOT use a WebView for auth.
- Redirect URI is a CUSTOM URL SCHEME (e.g. com.yourapp://callback) declared as an
  <intent-filter> in AndroidManifest.xml. EntryIdP does NOT support App Links — do not
  configure assetlinks.json.
- Persist AppAuth AuthState in EncryptedSharedPreferences (Android Keystore-backed). It
  holds both access and refresh tokens.

Login vs enrol (EntryIdP-specific):
- "Sign in" → standard AuthorizationRequest (login of an existing face).
- "Create account" → setAdditionalParameters(mapOf("prompt" to "create"))
  (first-time face enrolment).
- If the result is error=access_denied with error_description=user_not_registered,
  retry with prompt=create.

Guardrails:
- No sign-in form, OTP, or social-login UI.
- No client_secret.
- No WebView for authentication; no App Links.
- Custom URL scheme redirect only; endpoints from discovery, not hardcoded.

Done? Run through the pre-launch checklist before you ship, and see Refresh tokens rotate if you requested offline_access.

EntryIdP — Synapser