Skip to content

iOS — native (Swift + AppAuth-iOS)

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

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

Follow the guide

A — Login vs enrol

  • Login: build the authorization request as usual → /authorize.
  • Enrol: add prompt=create via OIDAuthorizationRequest's additionalParameters/authorize?prompt=create.

Choose one of:

  • Option 1 (recommended): two buttons — "Sign in" and "Create account" — the latter passing ["prompt": "create"].
  • Option 2: attempt login; if the redirect returns error=access_denied with error_description=user_not_registered, retry with prompt=create.

B — Redirect callback setup

  • Use ASWebAuthenticationSession (AppAuth uses it under the hood). Do not use WKWebView — Apple rejects apps that put auth in an embedded web view.
  • Symbol names (AppAuth-iOS 1.7.x): drive the flow with OIDExternalUserAgentIOS(presenting:) (a presenting UIViewController) — there is no OIDExternalUserAgentASWebAuthenticationSession type. Read OAuth errors via OIDOAuthErrorResponseErrorKey in userInfo (not OIDOAuthErrorResponseKey).
  • Use a custom URL scheme. EntryIdP does not host apple-app-site-association, so Universal Links are not available.
  • Register the scheme in Info.plist under CFBundleURLTypes. The redirect URI (e.g. com.yourapp://callback) must exactly match what was registered for your client.

C — Secure token storage

TokenWhere
Access tokenKeychain — persist AppAuth's OIDAuthState (e.g. via NSKeyedArchiver / encode(with:)).
Refresh tokenSame Keychain entry — AppAuth's OIDAuthState bundles both tokens.

Use an AI prompt

Add EntryIdP biometric OIDC login to this native iOS app (Swift) using AppAuth-iOS.

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 configuration — never hardcode).

Before writing code:
1. Confirm the dependency manager (SPM / CocoaPods) and add AppAuth-iOS if missing.
2. Find Info.plist and AppDelegate / SceneDelegate to wire up the redirect.

Implementation:
- Authorization Code + PKCE only (AppAuth adds PKCE automatically with S256). Never use
  implicit flow or response_type=token.
- PUBLIC client: no client_secret anywhere.
- Discover config with OIDAuthorizationService.discoverConfiguration(forIssuer:).
- Use ASWebAuthenticationSession (AppAuth default). Do NOT use WKWebView for auth.
- Use the correct AppAuth-iOS symbol names (verified against 1.7.x — do NOT invent variants):
    * External user agent: OIDExternalUserAgentIOS(presenting: viewController). It uses
      ASWebAuthenticationSession internally and takes a PRESENTING UIViewController — NOT an
      ASWebAuthenticationPresentationContextProviding. There is NO type named
      OIDExternalUserAgentASWebAuthenticationSession.
    * OAuth error key: OIDOAuthErrorResponseErrorKey (in userInfo). There is NO
      OIDOAuthErrorResponseKey. To read error_description use OIDOAuthErrorFieldErrorDescription.
- Redirect URI is a CUSTOM URL SCHEME (e.g. com.yourapp://callback) registered in
  Info.plist under CFBundleURLTypes. EntryIdP does NOT support Universal Links — do not
  configure apple-app-site-association.
- Persist OIDAuthState to the Keychain (it holds both access and refresh tokens). Never
  store tokens in UserDefaults.

Login vs enrol (EntryIdP-specific):
- "Sign in" → standard authorization request (login of an existing face).
- "Create account" → same request with additionalParameters ["prompt": "create"]
  (first-time face enrolment).
- If the auth response returns 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 WKWebView for authentication; no Universal 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