Skip to content

Authentication

Basic Authentication Configuration with In-Memory Credential Store

// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance());

// Uses built-in memory store for storing credentials.
ClientProvider.set(new OkHttpClient.Builder()
        .addInterceptor(new AppHeadersInterceptor())
        .authenticator(new BasicAuthDialogAuthenticator())
        .cookieJar(new WebkitCookieJar())
        .build());
// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance())

// Uses built-in memory store for storing credentials.
ClientProvider.set(OkHttpClient.Builder()
        .addInterceptor(AppHeadersInterceptor())
        .authenticator(BasicAuthDialogAuthenticator())
        .cookieJar(WebkitCookieJar())
        .build())

Basic Authentication Configuration with Persistent Credential Store

// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance());

class PersistentCredentialStore implements BasicAuthCredentialStore {
    private final String KEY_PREFIX = "key prefix";
    private final String STORE_NAME = "secure store name";
    private final Logger logger =
            LoggerFactory.getLogger(PersistentCredentialStore.class);
    private final SecureKeyValueStore secureKeyValueStore;

    PersistentCredentialStore(Context context) {
        secureKeyValueStore = new SecureKeyValueStore(context, STORE_NAME);
        try {
            secureKeyValueStore.open(null);
        } catch (OpenFailureException e) {
            logger.error(e.getMessage());
        }
    }

    @Override
    public void storeCredential(@NonNull String host,
                                @NonNull String realm,
                                @NonNull String[] credential
    ) {
        secureKeyValueStore.put(key(host, realm), credential);
    }

    @Override
    public String[] getCredential(@NonNull String host, @NonNull String realm) {
        return secureKeyValueStore.getSerializable(key(host, realm));
    }

    @Override
    public void deleteCredential(@NonNull String host, @NonNull String realm) {
        secureKeyValueStore.remove(key(host, realm));
    }

    @Override
    public void deleteAllCredentials() {
        secureKeyValueStore.removeAll();
    }

    private String key(String host, String realm) {
        return KEY_PREFIX + host + "::" + realm;
    }

    public void close() {
        secureKeyValueStore.close();
    }
}

PersistentCredentialStore credentialStore = new PersistentCredentialStore(this);
ClientProvider.set(new OkHttpClient.Builder()
        .addInterceptor(new AppHeadersInterceptor())
        .authenticator(
                new BasicAuthDialogAuthenticator(credentialStore))
        .cookieJar(new WebkitCookieJar())
        .build());

// Remembers to close the store when application is closed.
credentialStore.close();
// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance())

// PersistentCredentialStore is a custom implementation of
// BasicAuthCredentialStore that uses secure store for storing credentials.
class PersistentCredentialStore(context: Context) : BasicAuthCredentialStore {
    private var secureKeyValueStore: SecureKeyValueStore

    init {
        secureKeyValueStore = SecureKeyValueStore(context, STORE_NAME)
        try {
            secureKeyValueStore.open(null)
        } catch (e: OpenFailureException) {
            logger.error(e.message)
        }
    }

    override fun storeCredential(
        host: String, realm: String, credential: Array<String>
    ) {
        secureKeyValueStore.put(key(host, realm), credential)
    }

    override fun getCredential(host: String, realm: String): Array<String>? {
        return secureKeyValueStore.getSerializable(key(host, realm))
    }

    override fun deleteCredential(host: String, realm: String) {
        secureKeyValueStore.remove(key(host, realm))
    }

    override fun deleteAllCredentials() {
        secureKeyValueStore.removeAll()
    }

    private fun key(host: String, realm: String): String {
        return "${KEY_PREFIX}$host::$realm"
    }

    fun close() {
        secureKeyValueStore.close()
    }

    companion object {
        private const val KEY_PREFIX = "key prefix"
        private const val STORE_NAME = "secure store name"
        private val logger =
                LoggerFactory.getLogger(PersistentCredentialStore::class.java)
    }
}

val credentialStore = PersistentCredentialStore(this)
ClientProvider.set(OkHttpClient.Builder()
        .addInterceptor(AppHeadersInterceptor())
        .authenticator(
                BasicAuthDialogAuthenticator(credentialStore))
        .cookieJar(WebkitCookieJar())
        .build())

// Remembers to close the store when application is closed.
credentialStore.close()

SAML Authentication Configuration

// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance());

ClientProvider.set(new OkHttpClient.Builder()
        .addInterceptor(new AppHeadersInterceptor())
        .addInterceptor(new SamlInterceptor())
        .cookieJar(new WebkitCookieJar())
        .build());
// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance())

ClientProvider.set(OkHttpClient.Builder()
        .addInterceptor(AppHeadersInterceptor())
        .addInterceptor(SamlInterceptor())
        .cookieJar(WebkitCookieJar())
        .build())

SAML Authentication Configuration with Authentication URL

// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance());

ClientProvider.set(new OkHttpClient.Builder()
        .addInterceptor(new AppHeadersInterceptor())
        .addInterceptor(new SamlInterceptor(
                new SamlConfiguration.Builder().authUrl(
                        SettingsProvider.get().getBackendUrl()
                                + "/SAMLAuthLauncher").build()))
        .cookieJar(new WebkitCookieJar())
        .build());
// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance())

ClientProvider.set(OkHttpClient.Builder()
        .addInterceptor(AppHeadersInterceptor())
        .addInterceptor(SamlInterceptor(
                SamlConfiguration.Builder().authUrl(
                        SettingsProvider.get().backendUrl
                                + "/SAMLAuthLauncher").build()))
        .cookieJar(WebkitCookieJar())
        .build())

SAML Authentication Configuration with WebView

// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance());

ClientProvider.set(new OkHttpClient.Builder()
        .addInterceptor(new AppHeadersInterceptor())
        .addInterceptor(new SamlInterceptor(new SamlWebViewProcessor(
                new SamlConfiguration.Builder().authUrl(
                        SettingsProvider.get().getBackendUrl()
                                + "/SAMLAuthLauncher").build())))
        .cookieJar(new WebkitCookieJar())
        .build());
// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance())

ClientProvider.set(OkHttpClient.Builder()
        .addInterceptor(AppHeadersInterceptor())
        .addInterceptor(SamlInterceptor(SamlWebViewProcessor(
                SamlConfiguration.Builder().authUrl(
                        SettingsProvider.get().backendUrl
                                + "/SAMLAuthLauncher").build())))
        .cookieJar(WebkitCookieJar())
        .build())

SAML Authentication Configuration for Certificate-Based Authentication

// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance());

ClientProvider.set(new OkHttpClient.Builder()
        .addInterceptor(new AppHeadersInterceptor())
        .addInterceptor(new SamlInterceptor(new SamlWebViewProcessor(
                new SamlConfiguration.Builder().authUrl(
                        SettingsProvider.get().getBackendUrl()
                                + "/SAMLAuthLauncher").build(),
                // System certificate provider presents a dialog
                // to select a certificate
                new SystemCertificateProvider())))
        .cookieJar(new WebkitCookieJar())
        .build());
// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance())

ClientProvider.set(OkHttpClient.Builder()
        .addInterceptor(AppHeadersInterceptor())
        .addInterceptor(SamlInterceptor(SamlWebViewProcessor(
                SamlConfiguration.Builder().authUrl(
                        SettingsProvider.get().backendUrl
                            + "/SAMLAuthLauncher").build(),
                // System certificate provider presents a dialog
                // to select a certificate
                SystemCertificateProvider())))
        .cookieJar(WebkitCookieJar())
        .build())

OAuth Authentication Configuration with WebView

// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance());

// PersistentTokenStore is a custom implementation of OAuth2TokenStore that
// uses secure store for storing credentials.
class PersistentTokenStore implements OAuth2TokenStore {
    private final String KEY_PREFIX = "key prefix";
    private final String STORE_NAME = "secure store name";
    private final Logger logger =
            LoggerFactory.getLogger(PersistentTokenStore.class);
    private final SecureKeyValueStore secureKeyValueStore;

    PersistentTokenStore(Context context) {
        secureKeyValueStore = new SecureKeyValueStore(context, STORE_NAME);
        try {
            secureKeyValueStore.open(null);
        } catch (OpenFailureException e) {
            logger.error(e.getMessage());
        }
    }

    @Override
    public void storeToken(@NonNull OAuth2Token oauth2Token,
                            @NonNull String url) {
        secureKeyValueStore.put(key(url), oauth2Token);
    }

    @Override
    public OAuth2Token getToken(@NonNull String url) {
        return secureKeyValueStore.getSerializable(key(url));
    }

    @Override
    public void deleteToken(@NonNull String url) {
        secureKeyValueStore.remove(key(url));
    }

    private String key(String url) {
        return KEY_PREFIX + Uri.parse(url).getHost();
    }

    public void close() {
        secureKeyValueStore.close();
    }
}

// ClientId and Url values are displayed in SAP mobile service cockpit.
OAuthConfig oAuthConfig = new OAuthConfig.Builder()
        .authorizationEndpoint("http://authUrl")
        .tokenEndpoint("http://tokenUrl")
        .addClient(new OAuthClient.Builder()
                .clientID("clientID")
                .redirectURL("https://redirectUrl")
                .grantType(OAuth.RESPONSE_TYPE_CODE).build()
        ).build();
OAuth2WebViewProcessor oAuth2WebViewProcessor
        = new OAuth2WebViewProcessor(oAuthConfig);

PersistentTokenStore tokenStore = new PersistentTokenStore(this);
ClientProvider.set(new OkHttpClient.Builder()
        .addInterceptor(new AppHeadersInterceptor())
        .addInterceptor(new OAuth2Interceptor(oAuth2WebViewProcessor,
                tokenStore))
        .cookieJar(new WebkitCookieJar())
        .build());

// Remembers to close the store when application is closed.
tokenStore.close();
// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance())

// PersistentTokenStore is a custom implementation of OAuth2TokenStore that
// uses secure store for storing credentials.
class PersistentTokenStore(context: Context) : OAuth2TokenStore {
    private var secureKeyValueStore: SecureKeyValueStore

    init {
        secureKeyValueStore = SecureKeyValueStore(context, STORE_NAME)
        try {
            secureKeyValueStore.open(null)
        } catch (e: OpenFailureException) {
            logger.error(e.message)
        }
    }

    override fun storeToken(oauth2Token: OAuth2Token, url: String) {
        secureKeyValueStore.put(tokenKey(url), oauth2Token)
    }

    override fun getToken(url: String): OAuth2Token? {
        return secureKeyValueStore.getSerializable(tokenKey(url))
    }

    override fun deleteToken(url: String) {
        secureKeyValueStore.remove(tokenKey(url))
    }

    private fun tokenKey(url: String): String {
        return KEY_PREFIX + Uri.parse(url).host
    }

    fun close() {
        secureKeyValueStore.close()
    }

    companion object {
        private const val KEY_PREFIX = "key prefix"
        private const val STORE_NAME = "secure store name"
        private val logger =
            LoggerFactory.getLogger(PersistentTokenStore::class.java)
    }
}

// ClientId and Url values are displayed in SAP mobile service cockpit.
val oAuthConfig = OAuthConfig.Builder()
    .authorizationEndpoint("http://authUrl")
    .tokenEndpoint("http://tokenUrl")
    .addClient(OAuthClient.Builder()
        .clientID("clientID")
        .redirectURL("https://redirectUrl")
        .grantType(OAuth.RESPONSE_TYPE_CODE).build()
    ).build()
val oAuth2WebViewProcessor = OAuth2WebViewProcessor(oAuthConfig)

val tokenStore = PersistentTokenStore(this)
ClientProvider.set(OkHttpClient.Builder()
        .addInterceptor(AppHeadersInterceptor())
        .addInterceptor(OAuth2Interceptor(oAuth2WebViewProcessor,
                tokenStore))
        .cookieJar(WebkitCookieJar())
        .build())

// Remembers to close the store when application is closed.
tokenStore.close()

OAuth Authentication Configuration with Allowed Browsers

// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance());

// ClientId and Url values are displayed in SAP mobile service cockpit.
OAuthConfig oAuthConfig = new OAuthConfig.Builder()
        .authorizationEndpoint("http://authUrl")
        .tokenEndpoint("http://tokenUrl")
        .addClient(new OAuthClient.Builder()
                .clientID("clientID")
                .redirectURL("com.sap.scheme://redirectUrl")
                .grantType(OAuth.RESPONSE_TYPE_CODE).build()
        ).build();
ArrayList<BrowserDetails> allowedBrowsers = new ArrayList<>();
allowedBrowsers.add(BrowserDetails.chrome());
OAuth2BrowserProcessor oAuth2BrowserProcessor = new OAuth2BrowserProcessor(
        oAuthConfig,
        null,
        null,
        new BrowserWhitelist(allowedBrowsers));

// Following entry must be added to app `AndroidManifest.xml`
// to match the redirectUrl scheme above.
<activity android:name="com.sap.cloud.mobile.foundation.authentication.OAuth2RedirectActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="com.sap.scheme" />
    </intent-filter>
</activity>

ClientProvider.set(new OkHttpClient.Builder()
        .cookieJar(new WebkitCookieJar())
        .addInterceptor(new AppHeadersInterceptor())
        .addInterceptor(new OAuth2Interceptor(oAuth2BrowserProcessor,
                new OAuth2TokenInMemoryStore()))
        .build());
// Note: Registering the ActivityLifecycleCallback should be done in your
// application's onCreate method. AppLifecycleCallbackHandler must be registered
// for the authentication interceptors to display the UI to authenticate the user.
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance())

// ClientId and Url values are displayed in SAP mobile service cockpit.
val oAuthConfig = OAuthConfig.Builder()
    .authorizationEndpoint("http://authUrl")
    .tokenEndpoint("http://tokenUrl")
    .addClient(
        OAuthClient.Builder()
            .clientID("clientID")
            .redirectURL("com.sap.scheme://redirectUrl")
            .grantType(OAuth.RESPONSE_TYPE_CODE).build()
    ).build()
val allowedBrowsers = ArrayList<BrowserDetails>()
allowedBrowsers.add(BrowserDetails.chrome())
val oAuth2BrowserProcessor = OAuth2BrowserProcessor(
    oAuthConfig,
    null,
    null,
    BrowserWhitelist(allowedBrowsers)
)

// Following entry must be added to app `AndroidManifest.xml`
// to match the redirectUrl scheme above.
<activity android:name="com.sap.cloud.mobile.foundation.authentication.OAuth2RedirectActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="com.sap.scheme" />
    </intent-filter>
</activity>

ClientProvider.set(
    OkHttpClient.Builder()
        .addInterceptor(AppHeadersInterceptor())
        .addInterceptor(
            OAuth2Interceptor(
                oAuth2BrowserProcessor,
                OAuth2TokenInMemoryStore()
            )
        )
        .cookieJar(WebkitCookieJar())
        .build()
    )

Disable Authentication Credentials Acquisition UI

// Any subsequent challenges from the server will not display the authentication UI,
// when the app UI should not be switched due to the impact on user experience.
// Note that the pending requests that require authentication will fail
// until credentials are acquired.
AuthenticationUiCallback doNotShowUI = new AuthenticationUiCallback() {
    @Override
    public boolean allowShowingUiToAuthenticate() {
        return false;
    }
};
AuthenticationUiCallbackManager.setAuthenticationUiCallback(doNotShowUI);
// Any subsequent challenges from the server will not display the authentication UI,
// when the app UI should not be switched due to the impact on user experience.
// Note that the pending requests that require authentication will fail
// until credentials are acquired.
val doNotShowUI = AuthenticationUiCallback { false }
AuthenticationUiCallbackManager.setAuthenticationUiCallback(doNotShowUI)

Last update: June 23, 2023