Desktop & mobile apps
Use a Desktop or mobile app client for installed apps. It follows RFC 8252 (OAuth 2.0 for Native Apps): sign-in runs in the system browser, the code comes back to your app, and PKCE protects it. There is no client secret.
Use the system browser
Open the authorization URL in the system browser, or in ASWebAuthenticationSession on iOS/macOS and Custom Tabs on Android.
Don't use embedded web views: your app could read the person's password from one, so people should not trust them.
Redirect URLs
Loopback (desktop)
Listen on 127.0.0.1, then register for example http://127.0.0.1:53111/callback.
Ports are matched exactly. If your app may use one of several ports, register each one.
Pick a few fixed ports and try them in order.
Custom scheme (mobile)
Use a private-use scheme in reverse-domain form, based on a domain you control: com.example.app:/callback.
Schemes without a dot are not accepted. On iOS and Android you can also use an https universal or app link that you own.
Libraries
- iOS / macOS: AppAuth-iOS (
OIDAuthorizationServicewith the discovery document). - Android: AppAuth-Android (
AuthorizationServiceConfiguration.fetchFromIssuer). - Windows / .NET: IdentityModel.OidcClient with a loopback listener.
// AppAuth-Android (Kotlin)
AuthorizationServiceConfiguration.fetchFromIssuer(Uri.parse("https://auth.motaware.com")) { config, ex ->
val request = AuthorizationRequest.Builder(
config!!, "mw_yourclientid", ResponseTypeValues.CODE,
Uri.parse("com.example.app:/callback"))
.setScopes("openid", "email", "profile", "offline_access")
.build() // AppAuth adds PKCE (S256) by default
startActivityForResult(authService.getAuthorizationRequestIntent(request), RC_AUTH)
}
Storing tokens
Ask for offline_access to get a refresh token, and keep it in the platform's secure store:
Keychain on Apple platforms, the Keystore on Android, Credential Manager or DPAPI on Windows.
Refresh tokens may be rotated: always store the newest one.