Appearance
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=createviaOIDAuthorizationRequest'sadditionalParameters→/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_deniedwitherror_description=user_not_registered, retry withprompt=create.
B — Redirect callback setup
- Use
ASWebAuthenticationSession(AppAuth uses it under the hood). Do not useWKWebView— 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 presentingUIViewController) — there is noOIDExternalUserAgentASWebAuthenticationSessiontype. Read OAuth errors viaOIDOAuthErrorResponseErrorKeyinuserInfo(notOIDOAuthErrorResponseKey). - Use a custom URL scheme. EntryIdP does not host
apple-app-site-association, so Universal Links are not available. - Register the scheme in
Info.plistunderCFBundleURLTypes. The redirect URI (e.g.com.yourapp://callback) must exactly match what was registered for your client.
C — Secure token storage
| Token | Where |
|---|---|
| Access token | Keychain — persist AppAuth's OIDAuthState (e.g. via NSKeyedArchiver / encode(with:)). |
| Refresh token | Same 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.