Secure your native applications, like mobile and desktop applications using IdentityServer

Securing Native Applications

Investigating how native applications can be integrated and secured with OpenID Connect and OAuth 2.0 - using Duende Identity Server

Native applications are applications that have access to the operating system's native APIs and features. This means they can interact with the system in ways that are not possible with web applications. Examples of native applications include mobile applications, desktop applications, and even some types of web applications. They can access features of the operating system, especially for secure data storage.

How Can a Native App Interact with Authentication Servers?

A common (but deprecated) approach is to create a login page within the native app, allow users to enter their credentials, and then send them to the authentication server using the Resource Owner Password Credentials Grant flow. The native app then receives an access token from the authentication server and can use it to access the resource server.

This is NOT a secure approach. The native app has access to the user's credentials and can potentially be compromised or hacked.

Why Resource Owner Password Credentials Grant is Deprecated

This approach is currently deprecated because user secrets should only be known at the level of the authentication server. With the Resource Owner Password Credentials Grant:

  • Credentials are exposed in the application, which might even be a third-party application
  • No single sign-on (SSO) capability since there is no browser session that can use the session cookie set by the authentication server
  • No multi-factor authentication (MFA) support in most implementations
  • Increased security risk as the app handles sensitive credentials directly
  • Federation gateway pattern impossible - external authentication providers such as Google, Microsoft, or enterprise identity providers cannot be integrated, limiting users to only local accounts
  • Login logic not centralized - each native app must implement its own login UI and validation logic, leading to inconsistent user experiences and potential security gaps across different applications
  • Limited to password authentication only - modern authentication methods like biometrics, hardware security keys (FIDO2/WebAuthn), magic links, one-time codes, or passwordless flows cannot be supported
The OAuth 2.0 Security Best Current Practice document officially deprecates the Resource Owner Password Credentials Grant. Learn more in RFC 6819 - OAuth 2.0 Threat Model and Security Considerations and the updated OAuth 2.0 Security Best Current Practice.

Native applications should use the Authorization Code Flow with Proof Key for Code Exchange (PKCE) as specified in RFC 7636. This approach:

  • Launches the system browser for authentication
  • Keeps credentials within the authentication server
  • Supports SSO and MFA
  • Prevents authorization code interception attacks
  • Follows OAuth 2.0 best practices for native apps
  • Enables federation with external identity providers (Google, Microsoft, GitHub, etc.)
  • Supports enterprise identity providers (SAML, Azure AD, Okta, etc.)
  • Supports all modern authentication methods including biometrics, hardware keys, passwordless flows, and passkeys
  • Provides consistent authentication experience across all applications

How It Works: Browser-Based Authentication

To securely handle authentication, a browser should be used so that login can be safely managed by the identity provider. The browser handles the front-channel part of the OAuth 2.0 flow and is responsible for obtaining the authorization code. The app itself can then exchange the code for a token, and the tokens can be safely stored in the app using the secure data storage capabilities of the platform.

Why Not Use Embedded WebViews?

Some platforms provide embedded browser components that can display web pages, often called WebViews. However, using WebViews for authentication is considered an anti-pattern because:

  • The component is controlled by the hosting application
  • It could read keystrokes or inject malicious JavaScript
  • It still does not provide single sign-on (SSO) functionality out of the box
  • Users cannot use browser extensions such as password managers
  • Security features of the system browser are unavailable
  • Violates OAuth 2.0 best practices outlined in RFC 8252
Never use embedded WebViews for authentication. They create security vulnerabilities and violate OAuth 2.0 best practices for native applications.

Use the System Browser Instead

A better option is to use the system browser - the default browser of the operating system. This provides:

  • Single sign-on (SSO) across applications
  • Full browser security features and extensions
  • Shared authentication state across apps
  • Password manager integration
  • User trust - users can verify the domain in the address bar

Every major mobile platform provides a special version of the system browser hardened for authentication use cases:

Solving the Redirect URI Problem

The Authorization Code flow works with a redirect URI that the authentication server uses to callback the application. Web apps live on a specific URL, but native apps don't have a traditional web address. So what do we use as the redirect URL?

How URI Association Works

The solution lies in the fact that URLs can be associated with an application in the OS. When specific URIs are called, the associated app can automatically be launched.

Example: When you click a Reddit link in your browser, the Reddit mobile app automatically opens (if installed).

Here's how it works for authentication:

  1. Your app claims a redirect URI (e.g., app.test.com/callback)
  2. The authentication server is configured to accept that URL as a valid redirect URI
  3. When the authorize endpoint is called, the redirect URI is passed as a parameter
  4. When the front-channel flow completes, the authorization code is returned using this redirect URI
  5. The app automatically opens (if it isn't already running)
  6. The code can be accessed by the native app
  7. The app exchanges the code for tokens using the token endpoint without needing browser assistance

URL Registration Options

There are two primary approaches for registering redirect URIs with native applications:

Use a regular HTTPS URL that your organization controls:

  • Format: https://app.test.com/callback
  • iOS: Universal Links (Documentation)
  • Android: App Links (Documentation)
  • Advantages:
    • More secure - requires domain ownership verification
    • Cannot be hijacked by malicious apps
    • Works seamlessly across platforms
    • Follows RFC 8252 recommendations
Best Practice: Use HTTPS URLs with Universal Links (iOS) or App Links (Android) for maximum security. This prevents other apps from intercepting your authorization codes.

2. Using Custom URL Schemes

Use a custom scheme unique to your application:

  • Format: com.test.app://callback
  • Advantages:
    • Simpler to implement
    • Works on older platforms
    • No web hosting required
  • Disadvantages:
    • Can potentially be claimed by other apps
    • Less secure than HTTPS URLs
    • Not recommended by RFC 8252
Custom URL schemes can be claimed by multiple apps on some platforms. If possible, use HTTPS URLs with Universal/App Links instead.

Implementing PKCE for Enhanced Security

PKCE (Proof Key for Code Exchange) adds an additional layer of security to the Authorization Code flow, specifically designed to protect against authorization code interception attacks in native applications.

How PKCE Works

  1. Code Verifier: App generates a cryptographically random string (43-128 characters)
  2. Code Challenge: App creates a SHA-256 hash of the code verifier
  3. Authorization Request: App sends the code challenge to the authorization server
  4. Token Request: App sends the original code verifier when exchanging the code for tokens
  5. Verification: Server validates that the code verifier matches the original code challenge

This ensures that even if an authorization code is intercepted, it cannot be exchanged for tokens without the original code verifier.

PKCE is mandatory for native applications according to OAuth 2.0 Security Best Current Practice. Always implement it in your native apps.

Token Management and Storage

Proper token management is critical for maintaining security in native applications.

Secure Token Storage

Use the secure data storage capabilities of the operating system to store tokens:

Never store tokens in plain text or in shared preferences/user defaults. Always use platform-specific secure storage mechanisms.

Refresh Token Handling

Implement proper refresh token rotation and revocation:

  • Rotation: Request new refresh tokens with each refresh operation
  • Revocation: Revoke refresh tokens at the revocation endpoint when:
    • User logs out
    • App is uninstalled
    • Security concerns arise
    • Token theft is suspected

Reference: OAuth 2.0 Token Revocation (RFC 7009)

Additional Security Considerations

  • Token Expiration: Use short-lived access tokens (5-15 minutes)
  • Binding Tokens: Consider using DPoP (RFC 9449) for sender-constrained tokens
  • Biometric Protection: Require biometric authentication before accessing stored tokens
  • Jailbreak/Root Detection: Implement runtime security checks

Comparison: Embedded WebView vs System Browser

FeatureEmbedded WebViewSystem Browser
Security⚠️ Unsafe - Controlled by app✅ Hardened for authentication
Single Sign-On❌ Not available✅ Shared across apps
Browser Features❌ Limited or none✅ Fully featured
Password Managers❌ Not accessible✅ Available
User Trust⚠️ Lower - No visible domain✅ Higher - Visible address bar
OAuth 2.0 Compliance❌ Violates RFC 8252✅ Follows best practices
MFA Support⚠️ Limited✅ Full support
Federation⚠️ Problematic✅ Seamless

Implementation Resources

Explore these resources to implement secure authentication in native applications:

OAuth 2.0 for Native Apps

RFC 8252 - Best practices for OAuth 2.0 in native applications

PKCE (RFC 7636)

Proof Key for Code Exchange specification

Duende IdentityServer

Documentation for Duende IdentityServer

OAuth 2.0 Security Best Practices

Current security recommendations for OAuth 2.0

OpenID Connect Core

OpenID Connect specification for identity federation

WebAuthn/FIDO2

Modern passwordless authentication standards

iOS Authentication

Apple's Authentication Services framework

Android Custom Tabs

Android Custom Tabs for authentication

Key Takeaways

When implementing authentication for native applications:

  1. Never use Resource Owner Password Credentials Grant - It's deprecated and insecure
  2. Use Authorization Code Flow with PKCE - The recommended approach for native apps
  3. Launch the system browser - Don't use embedded WebViews
  4. Implement proper redirect URI handling - Prefer HTTPS URLs over custom schemes
  5. Store tokens securely - Use platform-specific secure storage
  6. Implement refresh token rotation - Enhance security with proper token management
  7. Follow RFC 8252 - Adhere to OAuth 2.0 best practices for native applications