5 Authentication in MCS

In Oracle Mobile Cloud Service (MCS), all resources are secured and can only be accessed by authenticated users that are authorized to access those resources. As a mobile app developer, you enable one or more authentication methods in the mobile backend and then write app code to use one of these methods.

The authentication methods available are:

  • OAuth Consumer

  • HTTP Basic

  • Enterprise Single Sign-On (SSO)

    This method includes variants for browser-based SSO and use of third-party tokens.

  • Facebook Login

Before getting into the specifics of each authentication method, let’s go over how authentication relates to authorization:

  • Authentication is the process of identifying an individual, usually based on a user name and password, often in combination with other credentials such as an application key. Authentication ensures that the user is who he or she claims to be. This chapter explains how to use these features in your mobile apps.

  • Authorization is the process of determining what an individual has permission to do. After the user gains access through authentication, the system grants access according to the settings configured for the user. The MCS Mobile User Management features let you configure an intelligent authorization policy based on user roles. For an introduction to MCS Mobile User Management, see Set Up Mobile Users, Realms and Roles.

OAuth Consumer Authentication in MCS

The ability to use OAuth as your authentication mechanism is built in to all mobile backends and enabled by default. Whenever you create a mobile backend, the OAuth Consumer keys are generated for you.

To enable or disable OAuth Consumer as an authentication method:

  1. Open the mobile backend and select the Settings page.

  2. Under Access Keys, set the OAuth Consumer switch to ON or OFF.

For details on the access keys and environment details provided, see Mobile Backend Authentication and Connection Info.

Once you have these keys, you can use them in your apps. When using the MCS SDK for a given mobile platform, you insert these access keys in the configuration file provided by the SDK and then the SDK uses them when constructing calls to REST APIs associated with the mobile backend. If you are coding the REST calls manually, see Authenticating with OAuth in Direct REST Calls.

HTTP Basic Authentication in MCS

The ability to use HTTP Basic as your authentication mechanism is built in to all mobile backends and enabled by default.

To enable or disable HTTP Basic as an authentication method:

  1. Open the mobile backend and select the Settings page.

  2. Under Access Keys, set the HTTP Basic switch to ON or OFF.

    When switched to ON, the access keys that you need are displayed.

For details on the access keys and environment details provided, see Mobile Backend Authentication and Connection Info.

Once you have these keys, you can use them in your apps. When using the MCS SDK for a given mobile platform, you insert these access keys in the configuration file provided by the SDK and then the SDK uses them when constructing calls to REST APIs associated with the mobile backend. If you are coding the REST calls manually, see Authenticating with HTTP Basic in Direct REST Calls.

Enterprise Single Sign-On in MCS

If you want to use your own identity provider to authenticate users of your apps, you can enable Oracle Cloud’s single sign-on (SSO) capability to connect with that identity provider and then configure your mobile backends to use it. This is particularly useful if you are rolling out apps for your company’s employees and you want them to be able to sign into the apps using their existing employee login credentials. Similarly, this could work for consumer applications where the customers already have user accounts for corresponding web applications.

You can set up SSO to work in either of the following ways:

  • Third-Party SAML and JWT tokens. The app obtains a token from a trusted 3rd-party issuer, makes an API call to the MCS token exchange endpoint, and receives back an MCS-issued token, which you include as a bearer token on each subsequent MCS API call.

  • Browser-Based SSO through MCS. The app opens the MCS SSO URL in a browser and, after a series of redirects, displays the login screen of the remote identity provider. Once the user successfully enters their credentials, they receive an OAuth token, which you include as a bearer token on each subsequent MCS API call.

    In the case of JWT tokens, MCS uses the OpenID Connect discovery protocol.

Third-Party SAML and JWT Tokens

MCS supports the use of tokens from third-party providers in two cases:

  • With zero footprint SSO, where no user accounts are stored in Oracle Cloud. Instead, all of the information for the user, including user roles, is derived from the third-party token. Such users are referred to as virtual users.

  • With a token that identifies a user that has been provisioned in both Oracle Cloud and the third-party IdP. Roles are assigned to the users in MCS.

SAML Tokens and Virtual Users

If you have users set up in a third-party IdP that supports the SAML 2.0 spec, you can authenticate those users in MCS via SAML tokens.

Here are the general steps to get this to work with virtual users (in other words, without having to also provision the users in Oracle Cloud):

  1. You configure your mobile backend to use HTTP Basic authentication. (This is required for you to be able to get the token.)

    You do this by selecting the backend in MCS, selecting the backend’s Settings page, and setting the switch for HTTP Basic Authentication to ON.

    Note:

    To test authentication through the API Test page, you’ll need to enable SSO for your mobile backend. You can check if your instance of MCS is configured for SSO from the Settings page of the mobile backend. Select the Enable Single Sign-On option if it’s not selected. If you don’t see the Enable Single Sign-On checkbox, you need to enable SSO for your Oracle Cloud account. See Configuring Identity Management (SSO and OAuth). After SSO is set up, you may need to log out and back into MCS for it to take effect.
  2. Your administrator configures the IdP to generate a SAML token when the user logs in.

  3. Your administrator registers the third-party token issuer and one or more token certificates in MCS.

    As part of this process, she can also associate MCS roles with tokens in one of the following ways.

    • By designating MCS roles to be associated with all tokens based on a given certificate.

    • By deriving role names (that match existing MCS roles) from given token attributes.

    • By mapping given token attribute values to existing MCS roles (where the attribute values don’t already match the MCS names).

  4. You code your app to do the following:

    1. Obtain a token from the third-party IdP upon user login.

    2. Send that token to an MCS token exchange endpoint to get an MCS-issued token in return.

    3. Use the MCS token for all subsequent API calls to MCS.

Configuring SAML Tokens for Virtual Users
To enable the authentication of virtual users via SAML tokens, you need to create a SAML app in your IdP. This is a special app that mediates the creating and passing of the SAML tokens.
Though the workflow varies by IdP, you generally need to do the following key tasks:
  1. Create a SAML 2.0 app.
  2. Configure the SAML 2.0 app by specifying the following:
    1. Redirect URL.
      You’ll configure your app to use the redirect URL to obtain the token. How the token is obtained depends on the operating system you use (iOS or Android) . Avoid entering an address to an actual live site. Use a fictitious address URL request, for example,

      http://hostname/mobile/platform/sso/redirect

      Be sure the redirect URL you provide is formed correctly, that is it should match the expected redirect URL value.

    2. Audience.
      SAML tokens have the concept of an audience. An audience is the intended recipient of the SAML response (the token). It restricts the set of URLs against which the token can be used. You configure the audience to the URL for the MCS SSO token endpoint.
      You construct this endpoint by appending /mobile/platform/sso/exchange-token to your instance’s base URL. You can determine the base URL by opening any mobile backend in MCS, clicking its Settings tab, and looking in the Environment URLs section.
    3. An assertion that lists the applicable roles for the user.
Registering the Token Issuer in MCS

Before your apps can use tokens issued by a third-party IdP to authenticate with a backend, an administrator needs to register the IdP as a token issuer in MCS. Here are the steps:

  1. In MCS, click open the side menu icon and select Administration from the side menu.

  2. Select an environment and click Keys & Certificates.
  3. Click the Web Service and Token Certificates tab.

  4. Click Add and provide the following information:

    • In the Alias field, enter a unique identifiable name for the certificate.

    • In the text field, paste the definition of the token certificate that was provided by the identity provider.

  5. Click Save.

  6. Wait for the token certificate to be propagated in the system. This should take no longer than 10 minutes.

  7. Click the Token Issuers tab.

  8. Click New Issuer.

  9. Enter the name of the token issuer in the Name field under Issuer Details.

  10. Next to the Certificate Subject Names panel, click Add (+) .

  11. From the Select Certificate Subject Names dialog, select at least one name and click Save.

    Typically the name is the subject name of the token certificate you added previously.

  12. Back on the Token Issuers tab, click Rules.

  13. Select Enable Virtual User.

  14. Optionally, create a User Mapping rule to designate the name of the token’s attribute that identifies the user.

    See Configuring Rules for Certificate Subject Names for information on creating rules.

  15. Optionally, designate user roles and mappings. The next topic has more information on how this works.

  16. Click Save and Close.

Associating Roles with a SAML Token

If you want to set up role-based access for users that authenticate with SAML tokens, you do so when registering the token issuer in MCS. You have the following possibilities:

  • Use roles already defined in the token that match the names of MCS roles.

    You do this by creating a Role Attribute rule and providing a comma-separated list of token attribute names. The roles are then derived from the values of these attributes.

  • If the role names defined in the token don’t match role names defined in MCS, provide a mapping between the two.

    You do this by:

    1. Creating a Role Attribute rule and providing a comma-separated list of token attributes that contain the role names.

    2. Creating a Role Mapping rule to create a mapping between a role derived from the token (via the role attribute rule) with one or more MCS user roles.

      You can create multiple mappings.

  • Apply one or more MCS roles to all tokens issued with a given certificate (unless roles were already applied via the role attribute or role mapping rules).

    You do this by creating a Default Role rule.

See Configuring Rules for Certificate Subject Names for the steps to create rules.

Obtaining a SAML Token Programmatically
To obtain a SAML third-party token, you typically use an embedded browser. Here are the general steps:
  1. Create a delegate object (for iOS) or client (for Android) to intercept the web request that contains the token. The delegate (or client) implements a method that allows your app to preview any web requests. For iOS, create a UIWebViewDelegate object. For Android, create a WebViewClient object.

  2. Register the delegate or client object with the embedded browser.

  3. Modify the method to look for a form post URL.

    When the specified request is located, the method should extract the token from the post body and indicate to the browser to stop the request and close or hide the browser.

For either iOS or Android, you’ll need a web view class, a delegate (or client) class, and the delegate (or client) implementation method name.

For iOS, use the UIWebView object and the UIWebViewDelegate method:

#pragma mark - UIWebViewDelegate

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)
request navigationType:(UIWebVeiwNavigationType)navigationType

For Android, use the WebView client and the WebVewClient method:

public class MainActivity extends Activity {
    private  Activity mCtx;
    private static  final  String TAG = "TokenExchange";
    private String remoteIDPURL = "https://hostname/mobile/platform/sso/redirect/saml";
    private WebView myWebView = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.content_main);
        mCtx = MainActivity.this;
        myWebView = (WebView) findViewById(R.id.webview);
        initWebView();
    }
private class MyBrowser extends WebViewClient {
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler,
SslError error){
            handler.proceed();
        }
@Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
           if(url.contains("http://localhost:port")) {
               // get value of SAMLResponse form field
                myWebView.loadUrl("javascript:window.HtmlViewer.showHTML" +
"('<html>'+document.getElementsByName('SAMLResponse')[0].value+'</html>');");
            }
        }
    }
class MyJavaScriptInterface
    {
        @JavascriptInterface
        @SuppressWarnings("unused")
        public void showHTML(String html){
            Log.i(TAG, "===== html is "+html);
            String samlToken = html.substring(html.indexOf("<html>") + 6,
html.indexOf("</html>"));
            Log.i(TAG, "SAML Token = " + samlToken);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    myWebView.stopLoading();
                    myWebView.setVisibility(View.INVISIBLE);
                    myWebView.destroy();
                    finish();
                }
            });
        }
    }
private void initWebView(){
        myWebView.setWebViewClient(new MyBrowser());
        myWebView.getSettings().setJavaScriptEnabled(true);
        myWebView.addJavascriptInterface(new MyJavaScriptInterface(),
"HtmlViewer");
        myWebView.getSettings().setLoadWithOverviewMode(true);
        myWebView.getSettings().setUseWideViewPort(false);
        myWebView.loadUrl(remoteIDPURL);
    }
private void showMessage(final String message){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(mCtx, message, Toast.LENGTH_LONG).show();
            }
        });
    }
}

When the app is launched, it's directed to the remoteIDPURL. When you enter your login credentials, the page is redirected. The onPageStarted method intercepts the response and the showHTML method retrieves the token.

Extracting the SAML Assertion

After you’ve obtained a SAML token from an IdP, you need to decode it to extract the SAML assertion from its response. You then GZIP compress that assertion and base64 encode it again before submitting it to the MCS token exchange to receive an MCS token.

One way to extract the assertion is to follow these steps:
  1. Open a browser and enter the address for the identity provider:
    For example, if you configured a SAML token with AD FS: https://domain_name/adfs/ls/idpinitiatedsignon
    You’re taken to the Test Local Federation page.
  2. Enter the user name and password credentials for the user you created and click Sign In.
  3. After the page refreshes, select the SAML app you created and click Sign in again.

    You are redirected to the endpoint URL and the SAML token is displayed in the browser URL field.

  4. Copy the response beginning with SAML Response=.
  5. Since you’ll need to base64 decode and inflate the SAML response, go to a SAML decoder tool such as SAML Decoder at https://www.samltool.com/decode.php.
  6. Go to the base64 Decode and Inflate page and paste the response into the Decode and Inflate XML field.
  7. Click DECODE AND INFLATE XML.
  8. Extract the SAML assertion from the XML field.
  9. Gzip compress the extracted assertion.
  10. Base64 encode the assertion.
Now you can call the token exchange, pass the assertion, and receive the MCS token.
Using a SAML Token to Authenticate with MCS

Once you have obtained a valid SAML token, you can use it to authenticate with MCS. You do so by passing the token to MCS’s token exchange endpoint. In exchange, you get an OAuth token issued by MCS that can be used for subsequent API calls during the session.

MCS’s client SDKs support authentication via the token exchange. Here is some sample code you can use with those SDKs.

Android

private AuthorizationAgent mAuthorization; 
private MobileBackend mobileBackend; 

try {
  mobileBackend = MobileBackendManager.getManager().getMobileBackend(this);
} catch (ServiceProxyException e) {
      e.printStackTrace();
}

mAuthorization = mobileBackend.getAuthorization(AuthType.TOKENAUTH);

iOS

-(void) authenticateSSOTokenExchange: (NSString*) token
                    storeAccessToken:(BOOL) storeToken
                     completionBlock: (OMCErrorCompletionBlock) completionBlock;

Cordova and JavaScript

mcs.mobileBackend.setAuthenticationType(mcs.AUTHENTICATION_TYPES.token);
mcs.mobileBackend.authorization.authenticate(token).then(callback).catch(errorCallback);
Coding the SAML Token Exchange Manually

If you are not using a client SDK, you need to manually code your app to exchange that token for an MCS token, with which you then authenticate.

  1. In the app’s login sequence, call the MCS token exchange endpoint to exchange the third-party token for an MCS-issued OAuth token:

    • The token exchange request is a simple GET request with no parameters.

    • It must include an Authorization header of the form:

      Authorization: Bearer external-token

    • It must also include the oracle-mobile-backend-id header with the value of the Basic Auth mobile backend ID for the mobile backend that you’re using.

    The token exchange endpoint is formed by starting with the base URL for your environment (which you can get from the Settings page of a mobile backend) and appending /mobile/platform/sso/exchange-token.

  2. In all REST calls to MCS APIs, include the given token in the Authorization header.

    The header takes the form Bearer access-token.

    The access-token value includes the mobile backend ID from the original request so you don’t have to include the ID in a separate header.

JWT Tokens and Virtual Users

If you have users set up in a third-party IdP that supports JWT, you can authenticate those users in MCS via JWT tokens.

Here are the general steps to get this to work with virtual users (in other words, without having to also provision the users in Oracle Cloud):

  1. You configure your backend to use both HTTP Basic and OAuth Consumer authentication.

    You can do this by selecting the backend in MCS, selecting the backend’s Settings page, and setting the switches for HTTP Basic and OAuth Consumer authentication to ON.

  2. Your administrator configures the IdP to generate a JWT token when the user logs in.

  3. Your administrator registers the third-party token issuer via a policy in MCS.

    As part of this process, she can also associate MCS roles with tokens in one of the following ways.

    • By designating MCS roles to be associated with all tokens based on a given certificate.

    • By deriving role names (that match existing MCS roles) from given token attributes.

    • By mapping given token attribute values to existing MCS roles (where the attribute values don’t already match the MCS names).

  4. You code your app to do the following:

    1. Obtain a token from the third-party IdP upon user login.

    2. Send that token to an MCS token exchange endpoint to get an MCS-issued token in return.

    3. Use the MCS token for all subsequent API calls to MCS.

Note:

This mode of integrating with an IdP is based on enhanced features that are specific to working with JWT tokens (such as JWKS support) and includes other features, such as the ability to configure allowed audience values and username attribute. You can also use the process that is used for integrating with SAML-based IdPs, though this provides you with less flexibility. See SAML Tokens and Virtual Users.
Registering a JWT Token Issuer in MCS

Before your apps can use JWT tokens issued by a third-party IdP to authenticate with a backend, an administrator needs to register the IdP as a token issuer in MCS. Here’s how it works:

  1. You create a configuration that holds information that is needed to integrate with the token issuer. This integration takes the form of a JSON object.

  2. You flatten the configuration into a single line.

  3. You insert the configuration as the value of the Security_AuthTokenConfiguration policy.

    See Modifying an Environment Policy.

The following several topics provide some examples of creating the configuration file for a token issuer.

Minimal IdP Configuration

Here is an example of a configuration file that covers a basic use case, where:

  • The user name can be derived from the token’s sub claim.

  • The token issuer is configured so that you can use discovery to obtain the issuer's current keys and/or certificates.

  • You are using MCS’s virtual user (zero footprint) capability so that you don’t need to have corresponding records for the user in Oracle Cloud.

  • User roles are specified in a token attribute named roles.

  • The token’s audience (aud) claim is set to the JWT auth token endpoint for your MCS instance (MCS-BASE-URL/mobile/platform/auth/token) so there is no need to override the default audience validation behavior.

{
  "issuers": [
    {
      "issuerName": "TOKEN-ISSUER-URL", 
      "jwks": {
        "discoveryUri": "TOKEN-ISSUER-URL/.well-known/openid-configuration"
      },
      "virtualUserEnabled": true,
      "roleAttributes": [ 
        "roles"
      ]
    }
  ]
}
IdP Configuration with Audience

Here is an example of a configuration file that covers a basic use case, where:

  • The user name can be derived from the token’s sub claim.

  • The token issuer is configured so that you can use discovery to obtain the issuer's current keys and/or certificates.

  • You are using MCS’s virtual user (zero footprint) capability so that you don’t need to have corresponding records for the user in Oracle Cloud.

  • User roles are specified in a token attribute named roles.

  • The token’s audience (aud) claim is set to GUID-12345678-ABCD-EFAB-CDEF-123456789ABC (which is a value that does not match MCS’s auth token endpoint).

{

  "issuers": [
    {
      "issuerName": "TOKEN-ISSUER-URL",
      "audience": [
        "GUID-12345678-ABCD-EFAB-CDEF-123456789ABC"
      ],
      "jwks": {
        "discoveryUri": "TOKEN-ISSUER-URL/.well-known/openid-configuration"
      },
      "virtualUserEnabled": true,
      "roleAttributes": [
        "roles"
      ]
    }
  ]
}
IdP Configuration with Audience and Username Attribute

Here is an example of a configuration file that covers a basic use case, where:

  • The username is specified in the unique_name claim (rather than the sub claim).

  • The token issuer is configured so that you can use discovery to obtain the issuer's current keys and/or certificates.

  • You are using MCS’s virtual user (zero footprint) capability so that you don’t need to have corresponding records for the user in Oracle Cloud.

  • User roles are specified in a token attribute named roles.

  • The token’s audience (aud) claim is set to GUID-12345678-ABCD-EFAB-CDEF-123456789ABC (which is a value that does not match MCS’s auth token endpoint).

{

  "issuers": [
    {
      "issuerName": "BASE-TOKEN-ISSUER-URL",
      "usernameAttribute": "unique_name",
      "audience": [
        "GUID-12345678-ABCD-EFAB-CDEF-123456789ABC"
      ],
      "jwks": {
        "discoveryUri": "BASE-TOKEN-ISSUER-URL/.well-known/openid-configuration"
      },
      "virtualUserEnabled": true,
      "roleAttributes": [
        "roles"
      ]
    }
  ]
}
Associating Roles with a JWT Token

If you want to set up role-based access for users that authenticate with JWT tokens, you do so when registering the token issuer in MCS via the Security_AuthTokenConfiguration policy. You have the following possibilities:

  • Use roles already defined in the token that match the names of MCS roles.

    You do this by creating a roleAttributes array for the issuer and populate it with claims in the token that you want to derive roles from.

  • If the role names defined in the token don’t match role names defined in MCS, provide a mapping between the two.

    You do this by:

    1. Creating a roleAttributes array for the issuer and populate it with claims in the token that you want to derive roles from.

    2. Creating a roleMappings array rule to create a mapping between a role derived from the token (via the roleAttributes array) with one or more MCS user roles.

      You can create multiple mappings.

  • Apply one or more MCS roles to all tokens issued with a given certificate (unless roles were already applied via roleAttributes or roleMappings).

    You do this by creating a defaultRoles array.

  • Apply one or more MCS roles to all tokens issued with a given certificate (whether or not roles were already applied via roleAttributes or roleMappings).

    You do this by creating an issuerRoles array.

See JWT Configuration Reference for details on the syntax of the configuration file.

Converting a JSON Object to One Line

You might find it useful to have some tools to convert JSON objects from multi-line objects to single-line objects and vice versa. Here are some examples of Python commands that you can use for that purpose,

To output the JSON content in file /scratch/jsmith/authTokenConfig.json as a single line:

cat /scratch/jsmith/authTokenConfig.json | python -c 'import json,sys;obj=json.load(sys.stdin);print json.dumps(obj);'

To output the JSON content in file /scratch/jsmith/authTokenConfig.json in “pretty print" form:

cat /scratch/jsmith/authTokenConfig.json | python -c 'import json,sys;obj=json.load(sys.stdin);print json.dumps(obj, indent=4, sort_keys=False);'
JWT Configuration Reference

Here are the fields that can be used in the JSON object that serves as the configuration for a JWT identity provider.

Root Fields

  • issuers — Required. A JSON array of trusted issuers objects. Each trusted issuer is defined as a JSON object, with a combination of the following fields.

  • policyMinReloadInterval — Optional. If a token exchange request is received, and the specified issuer is not found in the configuration cache, the configuration cache will automatically be reloaded from the stored policy in order to check for changes, unless the amount of time since the last configuration cache reload is less than the policyMinReloadInterval. The default value for this interval is 10 seconds. The policyMinReloadInterval configuration field can be used to override the default value with a specified integer value in seconds.

  • policyMaxReloadInterval — Optional. If a token exchange request is received, if the elapsed time since the last time the configuration cache was reloaded is in excess of policyMaxReloadInterval, the configuration cache will automatically be reloaded from the stored policy in order to check for changes. The default value for this interval is 120 seconds. The policyMaxReloadInterval configuration field can be used to override the default value with a specified integer value in seconds.

  • certificatesMinReloadInterval — Optional. If a token exchange request is received, and a required certificate is not found in the certificates cache, the certificates cache will automatically be reloaded from Oracle Keystore Service (KSS) in order to check for changes, unless the amount of time since the last certificates cache reload is less than the certificatesMinReloadInterval. The default value for this interval is 10 seconds. The certificatesMinReloadInterval configuration field can be used to override the default value with a specified integer value in seconds.

  • certificatesMaxReloadInterval — Optional. If a token exchange request is received, if the elapsed time since the last time the certificates cache was reloaded is in excess of certificatesMaxReloadInterval, the certificates cache will automatically be reloaded from KSS in order to check for changes. The default value for this interval is 300 seconds. The certificatesMaxReloadInterval configuration field can be used to override the default value with a specified integer value in seconds.

Issuer Fields

  • issuerName — Required. A JSON string which specifies the issuer name. This value must match the value of the iss claim in tokens from the associated token issuer.

  • enabled — Optional. A JSON boolean which can be used to enable or disable the token issuer. If the token issuer is disabled, any attempt to exchange a token from that issuer will fail. The default value is true.

  • audience — Optional. A JSON array of string values, specifying valid audience values for the external token. If the external token contains an aud claim and none of the associated values exactly matches one of the values in the specified list, then the external token will be treated as invalid.

    The default behavior if this field is not specified (or contains an empty list) is to compare the aud values in the external token to the following values:
    • base-URL

    • base-URL/

    • base-URL/mobile

    • base-URL/mobile/

    • base-URL/mobile/platform

    • base-URL/mobile/platform/

    • base-URL/mobile/platform/auth

    • base-URL/mobile/platform/auth/

    • base-URL/mobile/platform/auth/token

    • base-URL/mobile/platform/auth/token/

    If none of the aud values in the external token match any of the above values, the external token will be treated as invalid.

  • virtualUserEnabled — Optional. If true the virtual user (zero footprint) feature is enabled for this issuer, meaning your users can authenticate with third-party tokens without having corresponding user accounts in Oracle Cloud. The default value is false.

  • usernameAttribute — Optional. A JSON string specifying the name of a JWT token claim from which a username is extracted. If no value is provided, the value of the sub claim will be used as the username.

  • requireClientAuth — Optional. A JSON boolean which can be used to configure whether client authentication is required for this token issuer.

    • If the value is true, full client authentication is required.

    • If the value is false, a token exchange request can contain a client-id value in the POST body, with no client_secret value provided. This is intended only for cases where devices are not able to protect the client_secret.

    The default value is true.

  • clientIdAttribute — Optional. A JSON string specifying the name of a JWT token claim which contains the client ID of the OAuth client on the external token issuer which was used to obtain the external token. If a clientIdAttribute value is specified, the specified attribute is present in a token, and its value matches the username associated with the token, then the token exchange request will be rejected, because client tokens shouldn’t be exchanged for MCS user tokens.

    If no clientIdAttribute value is provided, this check will not be performed.

  • tokenTimeoutSeconds — Optional. A JSON integer specifying the token lifetime (i.e. from iat to exp) in seconds for MCS tokens issued in exchange for tokens from this issuer. If this field is not specified, the token lifetime will be governed by the Security_TokenExchangeTimeoutSecs policy. If the Security_TokenExchangeTimeoutSecs policy has not been defined, the default token lifetime is 28800 seconds (i.e. 8 hours).

    The token lifetime is also governed by the tokenTimeoutPolicy.

  • tokenTimeoutPolicy — Optional. A JSON string specifying the policy used to control the token lifetime (i.e. from iat to exp) for MCS tokens issued in exchange for tokens from this issuer. Three policy values are supported:

    • FromTimeoutSecs — The token lifetime is governed by the tokenTimeoutSeconds value.

    • FromExternalToken — The MCS-issued token will expire at the same time the external token being exchanged will expire (i.e. tokenTimeoutSeconds is ignored).

    • FromExternalTokenLimitedByTimeoutSecs — The MCS-issued token will expire at the same time the external token being exchanged or after the token timeout value, whichever comes first.

    If this field is not specified, the token timeout policy lifetime will be governed by the Security_TokenExchangeTimeoutPolicy policy. If the Security_TokenExchangeTimeoutPolicy policy has not been defined, the default token timeout policy is FromTimeoutSecs.

  • jwks— Optional. A JSON object which specifies the URI(s) and other configuration options associated with loading keys and/or certificates from the external token issuer on the fly.

    Use this object if you are using a discovery URI to load keys and/or certificates (and you are not using a certificateSubjectNames object).

    See jwks Fields for the options.

  • certificateSubjectNames — Optional. A JSON array of strings containing a list of the certificate subject names of certificates that have been uploaded into MCS through the Administration tab’s Keys and Certificates page. (See Configuring a Web Service or Token Certificate.)

    Use this object if you are not using a discovery URI to load keys and/or certificates (and therefore are not using a jwks object).

  • filters — Optional. A JSON array of filter objects. Each filter is defined as a JSON object, with a combination of these fields:

    • name — Required. A JSON string specifying the name of an attribute or claim to which the filter will be applied.

    • type — Optional. A JSON string specifying whether the filter is an include filter or an exclude filter.

      An include filter is satisfied if the token contains a value which matches one or more of the specified filter values (i.e. presence of a "match" causes the filter to be satisfied). An exclude filter is satisfied if the token does not contains a value which matches any of the specified filter values (i.e. absence of a "match" causes the filter to be satisfied).

      The default value is include.

    • values — Required. A JSON array of string values which will be compared to the value of the attribute or claim in the external token as identified by the name field.

      Filter values may contain the * character as a wildcard for matching purposes.

    Each filter in the array must be satisfied in order for the external token to be considered valid.

    Note:

    If a filter is specified incorrectly or incompletely (e.g. missing name, invalid type, missing or empty values array) the filter will always be considered to be not satisfied. The rationale is that the admin who configured the filter was trying to filter out something, and if we cannot figure out what that something is, it is better to err on the side of caution, and reject the external token.
  • allowedMbes — Optional. A JSON array of JSON objects which identify mobile backends can be used with this token issuer.

    You can specify a mobile backend including the name and version, or by including just clientId.

    If this field isn’t specified, the issuer can be used with any mobile backend.

    Here are the possible entries:

    • name — Optional. A JSON string specifying the name of a mobile backend. If you include this field, you must also include version.

    • version — Optional. A JSON string specifying the mobile backend version. If you include this field, you must also include name.

    • clientId — Optional. A JSON string specifying the OAuth client ID of a mobile backend.

  • userMappingAttribute — Optional. A JSON string identifying the user attribute used to search for an Oracle Cloud user to be associated with the token exchange.

    This attribute is ignored if virtualUserEnabled is set to true.

    The string can have one of the following values:

    • uid — Search for an Oracle Cloud user whose username matches the username extracted from the external token.

    • mail — Search for an Oracle Cloud user whose email address matches the username extracted from the external token.

    The default value is uid.

    Note:

    If a usernameAttribute hasn’t been configured, the username extracted from the external token will be the value of the sub claim. If a usernameAttribute has been configured, the username extracted from the external token will be the value of the whatever claim is identified by the usernameAttribute value.
  • defaultRoles — Optional. A JSON array of strings, where each string is the name of an MCS role which should be granted to a virtual user in the case where no roleAttributes value has been configured or where a roleAttributes value is configured but the specified attributes are either absent from the external token or are empty. 

  • issuerRoles — Optional. A JSON array of strings, where each string is the name of an MCS role which should be always granted to a virtual user when a token from this external issuer is exchanged. The difference between default roles and issuer roles is that default roles are granted only when no roles have been found during processing of role attributes, while issuer roles are always granted.

  • roleAttributes — Optional. A JSON array of strings where each string is the name of a token attribute (i.e. claim) which should be searched for role values. If a specified token attribute is not present in the external token, no roles will be added for that attribute. Otherwise, the token attribute value will be processed as follows:

    • If the token attribute value contains a JSON string, the string value will be granted as a role, subject to role mapping (see theroleMappings field).

    • If the token attribute value contains a JSON array of JSON string values, each of the string values will be granted as a role, subject to role mapping.

    If no roleAttributes array is provided, the external token will not be searched for roles, and the roles to be granted to the user will be based on defaultRoles and/or issuerRoles configuration, where provided.

  • roleMappings — Optional. A JSON array of role mapping objects, each of which specifies a mapping from a token role value (i.e. a value obtained from roleAttributes) and one or more MCS roles. Use this field when the values derived from role attributes do not match MCS role names.

    Here are the fields for a role mapping object:

    • tokenRole — Required. A JSON string specifying a token role name.

    • mappedRoles — Required. A JSON array of string values. Each string value should match an MCS role name.

    .

jwks Fields

  • discoveryUri — Optional. A JSON string specifying the URI from which the token issuer's discovery information can be loaded. The discovery information provided by the external token issuer must be in accordance with the following specification:

    http://openid.net/specs/openid-connect-discovery-1_0.html

    The discovery URI for a token issuer will typically be of the form base-url/.well-known/openid-configuration, but MCS does not require this to be the case.

    If a discoveryUri is configured for a token issuer, the MCS token exchange service will make a GET request to that URL to obtain the discovery information as needed. Once the discovery information has been obtained, MCS will typically use the jwks_uri value specified in the discovery information to obtain the issuer's current keys and/or certificates.

    If no discoveryUri is configured, then a jwksUri value must be configured.

  • jwksUri — Optional. A JSON string specifying the URI from which the token issuer's JWKS information can be loaded. The information provided by the external token issuer must be in accordance with the following specification:   

    https://tools.ietf.org/html/rfc7517

    If a jwksUri is configured for a token issuer, the MCS token exchange service will make a GET request to that URL to obtain the current keys and/or certificates for that issuer as needed.

    If both a discoveryUri and a jwksUri are specified in the configuration, the configured jwksUri value will be used, overriding the value in the issuer's discovery information.

  • allowHttp — Optional. A JSON boolean indicating that HTTP discoveryUri and jwksUri values should be allowed.

    For security reasons, discoveryUri and jwksUri values for external token issuers in production should always use HTTPS URLs, so that the server providing the information can be verified using its SSL certificate. However, in certain non-production test scenarios, it may be helpful to allow HTTP URIs to be used.

    The default value is false.

  • minReloadInterval — Optional. If a token exchange request is received, and the key and/or certificate needed to validate the external token cannot be found, MCS will automatically reload the discovery and JWKS information in order to check for changes (e.g. key rotation), unless the amount of time since the discovery/JWKS reload is less than this value (in seconds, expressed as an integer).

    The default value is 60.

  • maxReloadInterval — Optional. If a token exchange request is received and if the elapsed time since the last time the discovery and JWKS information was reloaded is in excess of this value (in seconds, expressed as an integer), the discovery and JWKS information will automatically be reloaded from the external token issuer in order to check for changes.

    The default value is 28800 (i.e. 8 hours).

  • connectTimeout — Optional. A JSON integer specifying the default connect timeout for discovery and/or JWKS requests. The default is 30 seconds.

  • readTimeout — Optional. A JSON integer specifying the default read timeout for discovery and/or JWKS requests. The default is 60 seconds

  • tlsVersions — Optional. A JSON array of string values, listing the SSL/TLS which will be allowed when connecting to the external token issuer for Discovery and/or JWKS requests. Valid version names are:

    • SSL

    • SSLv2

    • SSLv3

    • TLS

    • TLSv1

    • TLSv1.1

    • TLSv1.2

    The default value is ["TLSv1.1", "TLSv1.2"].

    Note:

    Older SSL/TLS versions are considered insecure, and should be avoided.
  • authorizationHeader — Optional. A JSON string specifying an Authorization header value which should be included in discovery and/or JWKS requests. In most cases, discovery and JWKS web pages are public and no authorization is required. This property is intended primarily for test purposes (e.g. when setting up a custom service to act as a discovery and/or JWKS endpoint).

Obtaining a JWT Token Using an Embedded Browser
If you use an embedded browser to obtain JWT tokens, you’ll need to perform the following actions:
  1. Create a delegate object (for iOS) or client (for Android) to intercept the web request that contains the token. The delegate (or client) implements a method that allows your app to preview any web requests. For iOS, create a UIWebViewDelegate object. For Android, create a WebViewClient object.

  2. Register the delegate or client object with the embedded browser.

  3. Modify the method to look for a redirect URL or a form post URL, depending on how the IdP is configured to deliver it.

    When the specified request is located, the method should extract the token from the query string (or post body) and indicate to the browser to stop the request and close or hide the browser.

For either iOS or Android, you’ll need a web view class, a delegate (or client) class, and the delegate (or client) implementation method name.

For iOS, use the UIWebView object and the UIWebViewDelegate method:

#pragma mark - UIWebViewDelegate

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)
request navigationType:(UIWebVeiwNavigationType)navigationType

For Android, use the WebView client and the WebVewClient method:

public class MainActivity extends Activity {
    private  Activity mCtx;
    private static  final  String TAG = "TokenExchange";
    private String remoteIDPURL = "https://hostname/mobile/platform/sso/redirect/saml";
    private WebView myWebView = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.content_main);
        mCtx = MainActivity.this;
        myWebView = (WebView) findViewById(R.id.webview);
        initWebView();
    }
private class MyBrowser extends WebViewClient {
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler,
SslError error){
            handler.proceed();
        }
@Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
           if(url.contains("http://localhost:port")) {
               // get value of SAMLResponse form field
                myWebView.loadUrl("javascript:window.HtmlViewer.showHTML" +
"('<html>'+document.getElementsByName('SAMLResponse')[0].value+'</html>');");
            }
        }
    }
class MyJavaScriptInterface
    {
        @JavascriptInterface
        @SuppressWarnings("unused")
        public void showHTML(String html){
            Log.i(TAG, "===== html is "+html);
            String samlToken = html.substring(html.indexOf("<html>") + 6,
html.indexOf("</html>"));
            Log.i(TAG, "SAML Token = " + samlToken);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    myWebView.stopLoading();
                    myWebView.setVisibility(View.INVISIBLE);
                    myWebView.destroy();
                    finish();
                }
            });
        }
    }
private void initWebView(){
        myWebView.setWebViewClient(new MyBrowser());
        myWebView.getSettings().setJavaScriptEnabled(true);
        myWebView.addJavascriptInterface(new MyJavaScriptInterface(),
"HtmlViewer");
        myWebView.getSettings().setLoadWithOverviewMode(true);
        myWebView.getSettings().setUseWideViewPort(false);
        myWebView.loadUrl(remoteIDPURL);
    }
private void showMessage(final String message){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(mCtx, message, Toast.LENGTH_LONG).show();
            }
        });
    }
}

When the app is launched, it's directed to the remoteIDPURL (the redirect URL). When you enter your login credentials, the page is redirected. The onPageStarted method intercepts the response and the showHTML method retrieves the token

Obtaining a JWT Token Using a System Browser

If you use a system browser to obtain the token, your app must relinquish control to the system browser app. When the login process is complete, you’ll need to return control to your app. You can return control via a redirect to a custom app scheme for which your app has registered.

For either iOS or Android, you’ll need to perform the following actions:
  1. Register the custom scheme for your app as dictated by the operating system. The custom scheme URL tells the mobile OS that requests to the given scheme should be sent to your app.

  2. Edit your app to handle the redirection. You’ll need to implement a method to handle the incoming redirect, which contains the token.

Coding Your Android App to Obtain a JWT Token

For Android apps, you need to register a custom URL scheme and then code the app to handle requests associated with that scheme. You do this by editing the AndroidManifest.xml file:

<activity android:name=".MainActivity">
    <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="http"
           android:host="mytest.com"
           android:pathPrefix="/"/>
    </intent-filter>
</activity>

The following example shows how to extract the token from the custom URL scheme in the Android activity class:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.content_main);
    Uri uri = getIntent().getData();
    if(uri != null) {
        String token = uri.getQueryParameter("token");
        Logger.debug(TAG, "token is : " + token);
    }
}

When you open the link to mytest.com, you'll have the option to open the link with the app. This will launch the Android activity from where the JWT token is retrieved.

Coding Your iOS App to Obtain a JWT Token
To obtain a third-party token via a system browser for an iOS app, you need to perform the following actions:
  1. Declare a custom URL scheme by editing the app’s Info.plist configuration file.

    The scheme tells the mobile operating system to route to your app the request that contains the token.

  2. Edit your app to implement the method to handle requests associated with that scheme.

To register a custom URL scheme with your iOS app, you must include the CFBundleURLTypes in your app’s Info.plist file. CFBundleURLTypes is an array of dictionaries. Each dictionary defines a URL scheme that the app supports. CFBundleURLTypes contains the following keys:

  • CFBundleURLName - a string that contains the abstract name of the URL scheme. This name should be unique. To ensure the name is unique, specify it as a reverse DNS style of identifier, such as com.company.myscheme.

    This string is also used as a key in your app’s InfoPlist.strings file. The value of the key is the human-readable scheme name.

  • CFBundleURLSchemes - An array of string s that contain the URL scheme names. For example: http, mailto, tel, and sms.

    Note:

    If multiple third-party apps register to handle the same URL scheme, there’s no way to determine which app is given the scheme.

Here’s an example of how to implement support for the custom URL scheme:

<key>CFBundleURLTypes</key>    
<array>         
   <dict>             
       <key>CFBundleURLName</key>             
       <string>oracle.cloud.mobile.URLDemo</string>             
       <key>CFBundleURLSchemes</key>             
       <array>                 
           <string>urldemo</string>             
       </array>            
       <key>CFBundleTypeRole</key>             
      <string>Viewer</string>        
    </dict>     
</array>

This stipulates that any URL specifying the scheme, urlScheme, is redirected to your app.

When the iOS system browser encounters a URL with this custom scheme, it launches your app, if necessary, and passes the URL to your app delegate. To handle incoming URLs, your app delegate must implement the application:openURL:options: method. For example:

- (BOOL)application:(UIApplication*)application             
            openURL:(NSURL*)url             
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id>*)options 
{     
   NSLog(@"Open URL: %@", url.absoluteString);     
   NSLog(@"Open URL options: %@", options);     
   if ([url.scheme isEqualToString:@"urldemo"]) {         
      [self viewController].incomingURL = url;         
      return YES;     
   }     
   return NO; 
} 

This implementation parses the incoming URL and extracts a ‘token’ query argument and stores it in an instance variable for later use. The implementation assumes the token is passed via the URL’s query string. Your implementation might differ and the token could be stored somewhere else in the URL. After your app extracts the token from the URL, the token can be exchanged for an MCS-issued token.

If you’re not familiar with creating URL schemes or implementing them in your app, see Apple’s documentation, specifically Using URL Schemes to Communicate with Apps.

Using a JWT Token to Authenticate with MCS

Once you have obtained a valid JWT token, you can use it to authenticate with MCS. You do so by passing the token to MCS’s token exchange endpoint. In exchange, you get a token issued by MCS that can be used for subsequent API calls during the session.

MCS’s client SDKs support authentication via the token exchange. Here is some sample code you can use with those SDKs.

Android

private AuthorizationAgent mAuthorization; 
private MobileBackend mobileBackend; 

try {
  mobileBackend = MobileBackendManager.getManager().getMobileBackend(this);
} catch (ServiceProxyException e) {
      e.printStackTrace();
}

mAuthorization = mobileBackend.getAuthorization(AuthType.TOKENAUTH);

iOS

-(void) authenticateSSOTokenExchange: (NSString*) token
                    storeAccessToken:(BOOL) storeToken
                     completionBlock: (OMCErrorCompletionBlock) completionBlock;

Cordova and JavaScript

mcs.mobileBackend.setAuthenticationType(mcs.AUTHENTICATION_TYPES.token);
mcs.mobileBackend.authorization.authenticate(token).then(callback).catch(errorCallback);
Coding the JWT Token Exchange Manually

Once your mobile administrator has registered an IdP as a token issuer in your environment and you have code in your app to acquire a 3rd-party token, you can use the MCS client SDK for your platform to handle the complete login sequence.

If you are not using a client SDK, you need to code your app to exchange that token for an MCS token, with which you then authenticate.

In the app’s login sequence, you call the MCS token exchange endpoint to exchange the third-party token for an MCS-issued OAuth token.

The token exchange request is an HTTP POST request, with an application/x/www-form-urlencoded request body, to the token exchange URL: base-URL/mobile/platform/auth/token.

The token exchange request must provide:

  • The external token (a.k.a. "user assertion") being exchanged in the form assertion=external-token.

  • Client authentication for the MCS mobile backend for which a new token is being requested, to prove that it is a valid user of that mobile backend.

Client authentication can be provided in any of the following ways:

  • Encode the client_id and client_secret in basic auth form in the Authorization header.

    In this case, the following headers are required:

    Content-Type: application/x/www-form-urlencoded
    Authorization: Bearer Base64(client_id:client_secret)

    And the body of the POST must contain these values:

    grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
    assertion=external-token
    
  • Encode the client_id and client_secret as application/x/www-form-urlencoded form values in the POST body.

    In this case, the following header is required:

    Content-Type: application/x/www-form-urlencoded
    

    And the body of the POST must contain these values:

    grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
    assertion=external-token
    client_id=client-id
    client_secret=client-secret

    If this option is used, the client_secret can be omitted if the requireClientAuth value in the configuration is set to false for the given issuer. This option is provided for clients that are unable to securely protect a client secret value. Even if the client_secret is omitted, the client_id value must still be provided, in order to identify the MCS mobile backend for which a token is being requested.

  • Provide a valid client assertion as an application/x/www-form-urlencoded form value in the POST body.

    In this case, the following header is required:

    Content-Type: application/x/www-form-urlencoded
    

    And the body of the POST must contain these values, where client-token is client token obtained from Oracle Cloud for the OAuth client associated with the MCS mobile backend for which a user token is being requested.

    grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
    assertion=external-token
    client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
    client_assertion=client-token

If the token exchange is successful, the response will have a 200 status, and will include an application/json body similar to this:

{ 
    "access_token":"123456789iJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.abcdefiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk", 
    "token_type":"Bearer", 
    "id_token":null, 
    "expires_in":28800 }

Mapping Users from a Third-Party IdP to Oracle Cloud Users

It is also possible to have enable authentication with 3rd-party tokens where there are matching records for the users in Oracle Cloud. This enables you to apply roles to users directly in MCS.

For this matching to work, the following conditions apply:

  • The Oracle Cloud users have been assigned to the realm that your mobile backend uses.

  • When registering the token issuer in MCS, your mobile administrator didn’t select the Enable Virtual User option.

  • In SAML tokens, the subject must identify the user’s username as defined in Oracle Cloud.

  • In JWT tokens, the sub or prn attributes must identify either the user’s username or email address as defined in Oracle Cloud.

User roles can be applied in any of these ways:

  • By assigning roles to individual users on the Applications > Mobile User Management page of MCS.

  • By doing batch assignments of roles in the My Services dashboard of Oracle Cloud. To do this, you need to have the identity domain administrator role for your account in Oracle Cloud.

  • By having your administrator, in the process of registering the IdP as a token issuer in MCS, specify one or more mobile roles to give to users authenticated with this IdP (via the default role rule).

  • By having your administrator, in the process of registering the IdP as a token issuer in MCS, create rules to map information extracted from the token (such as role names) to MCS mobile roles (via role attribute rules).

    If the role names defined in the IdP don’t match the role names defined in MCS, your administrator can configure role apping rules to map the token role names to the MCS role names.

If you want to use this approach but don’t yet have user accounts set up in Oracle Cloud, follow the instructions at Importing Groups of Mobile Users Into MCS Using Oracle Cloud.

Getting a Single Sign-On OAuth Token through a Browser

For an app to authenticate through a single sign-on identity provider, it first needs to get an SSO OAuth token. Using the MCS SDK for your platform simplifies this process. However, if you are making the REST calls directly from your app (or you are testing API calls using another tool, such as cURL or Postman), you need to get the token manually.

  1. On the mobile backend’s Settings page, gather the following information:

    • (OAuth Consumer) Client ID

    • Base URL

  2. Form the SSO token endpoint by appending /mobile/platform/sso/exchange-token to the base URL.

  3. Form a URL that combines the SSO token endpoint and a query parameter for the client ID. For example:

    <SSO_Token_Endpoint>?clientID=<client_ID>
  4. Open a private or incognito browser window, paste the URL into the address bar, and press Enter.

    (You need to use an incognito or private window because cookies stored in your browser for whatever reason, such as from having logged in to MCS, will interfere with your SSO token request.)

  5. In the page that appears, enter the SSO user name and password and press Enter.

  6. Open a private or incognito browser window, paste the URL into the address bar, and press Enter.

    The browser window will then display your token.

    You can use this in any REST calls you make to APIs through that mobile backend.

Note:

If you want to obtain a new token, do it from a fresh incognito or private window. If you use the same window from which you previously obtained a token, the correct token might not be returned.

Enabling Browser-Based SSO through MCS

Setting up browser-based single sign-on (SSO) in MCS consists of steps both in MCS and in the Oracle Cloud My Services portal. To follow these steps, you need to have the identity domain administrator role for your Oracle Cloud account.

To set up SSO for a group of users, you need to:

  1. Create a realm in MCS for those users by following the steps at Creating Realms.

  2. Configure your Oracle Cloud identity domain to allow SSO.

    To do so, go to the Users section of the My Services portal. See Configuring Identity Management (SSO and OAuth). After SSO is set up, you may need to log out and back into MCS for it to take effect.

  3. Create user accounts in Oracle Cloud for the app users and have them assigned to the realm that you have just set up.

    These accounts correspond with the user accounts in your identity provider but only contain limited information, such as user name and email address. The password is not stored in the Oracle Cloud user account.

    To get user accounts set up, follow the instructions at Importing Groups of Mobile Users Into MCS Using Oracle Cloud.

  4. (Optional) Assign the roles to the users that they need to access the APIs. (This step assumes that the given APIs are role-based.)

    This step is not a prerequisite for developing APIs and mobile backends that use SSO as the authentication method. However, you might find it convenient to assign roles to the mobile users as they are created, especially if your team has decided on the mobile user roles to create and what users and APIs to associate them with.

    In addition, as an identity domain administrator, you can do batch assignments of roles in the My Services dashboard. Mobile app developers can use the Mobile User Management interface in MCS to assign roles, but only one at a time. This is useful for testing purposes, but might be cumbersome when setting up more than a handful of users.

Note:

If you’re not sure whether your instance of MCS is already configured to allow SSO, you can quickly check by opening the Settings page of any mobile backend, enabling OAuth Consumer authentication, and looking for the Enable SSO checkbox under the OAuth settings. If SSO isn’t configured for your identity domain, you’ll see the message SSO is not set up for your Oracle Cloud account.
Enabling Single Sign-On for a Mobile Backend
  1. Open the mobile backend and select the Settings page.
  2. Under Access Keys, make sure OAuth Consumer is enabled.
    The Enable Single Sign-On checkbox appears.
  3. Select Enable Single Sign-On.

    Note:

    If the Enable Single Sign-On checkbox does not appear, you need to enable SSO for your Oracle Cloud account. See Configuring Identity Management (SSO and OAuth).
After you enable single sign-on, an SSO token endpoint is displayed under Environment URLs. You use this token endpoint to obtain the SSO authentication token. When using the MCS SDK for a given mobile platform, you insert this token endpoint into the configuration file provided by the SDK and SDK code handles the obtaining of the token.
Getting an SSO Token Using Form Post Response Mode

If you want to use MCS’s SSO login feature with browser-based apps, you use the form post response type to get the OAuth token from the SSO token relay and have it posted back to the app through a redirect URI.

So that you don’t make yourself vulnerable to having OAuth tokens generated on your behalf and then sent to a URI out of your control, you also have to specify acceptable values for the redirect URI in the Security_SsoRedirectWhitelist environment policy.

To code the call to the SSO token relay:

  1. On the mobile backend’s Settings page, gather the following information:

    • (OAuth Consumer) Client ID

    • SSO token endpoint

  2. In your code, form a URL that combines the SSO token endpoint, a query parameter for the client ID, and a parameter for the redirect URI. For example:

    <SSO_Token_Endpoint>?clientID=<client_ID>&redirect_uri=<Redirect_URI>
  3. From your code, call that URL.

    When that URL is called, the app user is redirected to a login page where they can sign in.

To set the Security_SsoRedirectWhitelist environment policy, see Modifying an Environment Policy.

The value for the Security_SsoRedirectWhitelist environment policy is a comma-separated list of simple URL patterns. For example:

https://www.example.com, https://*.example2.com

The pattern https://www.example.com will match the URLs https://www.example.com/path1, https://www.example.com/path1/path2, and so on.

Similarly, the pattern http://www.example.com/path1 will match URLs http://www.example.com/path1, http://www.example.com/path1/path2, http://www.example.com/path1/path2/path3 and so on, but will not match URL http://www.example.com/other-path.

Here are some other rules for the environment policy value:

  • You must include the port, unless you are using the default port for the URL scheme. For example, the pattern http://www.example.com matches the URL http://www.example.com or the URL http://www.example.com:80, but not http://www.example.com:8080.

  • You can use an asterisk (*) as a wildcard character within a URL segment but it doesn't apply across dot (.), forward slash (/), or colon (:) characters.

    For example, https://example*:8080 would match https://example-source:8080, but it wouldn’t match https://example.com:8080. This restriction is designed to prevent matching unintended sites. (Imagine something like http://example.imposter.com:8080 which you would not want your wildcard to match.)

  • Simple path values don’t require a wildcard. For example, if a redirect URI of https://example.com/apps/customer is passed to the mobile backend and compared to the white list value in the above policy example, it will be accepted.

  • The protocol (https:// in the above example) must be included.

Testing APIs in a Mobile Backend with SSO Login

Once you add an API to a mobile backend with SSO login enabled, you can use the API tester with SSO as the authentication method. This helps you ensure that the API call works end to end. You can test with the MCS-issued SSO token or a token from a third-party provider.

To test a custom API with SSO login:

  1. Click side menu icon and select Applications > Mobile Backends from the side menu.

  2. Select your mobile backend and click Open.

  3. In the left navbar of the mobile backend, select APIs.

  4. Click the API that you want to test.

  5. If the user that you plan to authenticate in the test has not yet been assigned the role that is needed to access the API, click the Security navigation link and switch Login Required to OFF.

  6. Click the Endpoints navigation link and scroll to the endpoint that you want to test.

  7. From the Authentication Method dropdown, select Single Sign-On Token .

  8. Obtain a valid SSO token for the mobile backend.

    If you are using web SSO, the fastest way to do this is to:

    1. Mouse over the info tip next to the Single Sign-On Token field, select the token endpoint URL that is in the info tip, and select Copy from your browser’s menu (pressing Ctrl-C might not work).

    2. Open a private or incognito browser window, paste the URL into the address bar, and press Enter.

    3. In the page that appears, enter the SSO user name and password and press Enter.

      The token should appear in the page that is returned.

  9. In the Single Sign-On Token, text field, paste the SSO token.

    If you have a token from your third-party provider, you can paste it in this field to authentication.

  10. Click Test Endpoint.

    If successful, a test response will appear with an appropriate HTTP code, such as 200.

Token Expiration for SSO Login

When you use SSO as your login mode, the token expires after six hours by default, meaning that the app user will need to log in again after that time. The length of the timeout is governed by the Security_TokenExchangeTimeoutSecs policy, which is given in seconds. See Environment Policies for information on changing the policy.

Facebook Login in MCS

You can configure mobile backends to enable users to log in through Facebook. This mode of authentication is particularly useful for apps targeting consumers (as opposed to employees of your business).

When you enable users to log in to an app through Facebook, you can do the following things in the app:

  • Call any custom APIs that allow access with a social identity login.

  • In the implementation code of such custom APIs, use the custom code SDK to call MCS platform APIs (with the exception of any APIs that are role-based).

  • Register for notifications.

The main steps for setting up an app to use Facebook for login are:

  1. Registering the app itself with Facebook.

  2. Configuring Facebook login in the mobile backend that the app will be using.

    Note:

    This mobile backend can only be used for Facebook login. If you wish to have apps access the mobile backend using different authentication methods, you must create a separate mobile backend for that purpose.
  3. Configuring the app itself to use Facebook for logging in.

  4. In the mobile backend, adding custom APIs that allow access through Facebook login.

Registering an App for Login Through Facebook

Before you can enable login through Facebook, you need to register your app with Facebook using the Facebook SDK for your platform. From the registration process Facebook will give you a Facebook app ID and secret which you will next configure in MCS.

For details, see Facebook’s documentation at https://developers.facebook.com/docs/apps/register.

Enabling Facebook Login in a Mobile Backend

Once you have registered your app with Facebook, you can enable Facebook login in a mobile backend.
  1. In MCS, open the mobile backend and select the Settings page.
  2. Under Social Login, switch on Facebook.
  3. In the Facebook Settings dialog, enter the app ID and app secret that you obtained when registering the app with Facebook.
  4. On the same page, make sure that HTTP Basic authentication is enabled.
    (HTTP Basic authentication is needed for the first part of the authentication process when the app requests the Facebook access token.)

Note:

If you also want to make an app accessible through any other authentication method, create a separate mobile backend for which Facebook Login is not enabled. Then, in the configuration file provided by the MCS client SDK for the given platform (e.g. OMC.plist for iOS and oracle_mobile_cloud_config.xml for Android), add the details for that mobile backend. The app can then use both mobile backends, depending on how the user authenticates.

Configuring an App to Use Facebook Login

Once you have registered your app with Facebook and have configured a mobile backend to work with Facebook login, you can configure your app to log users in with their Facebook identities. You need to:

  • Specify that Facebook is the identity provider.

  • Provide the Facebook App ID.

  • Provide the mobile backend ID and HTTP Basic anonymous key.

The easiest way to get this working is by using the MCS client SDK for the app’s platform, which enables you to specify all of the credentials in a single configuration file. See The SDKs.

Adding APIs to a Mobile Backend with Facebook Login

You can add the following types of APIs to a mobile backend configured for Facebook login.

  • Custom APIs that have the Login Required switch set to OFF.

  • Custom APIs that have the Login Required switch set to ON and the Social Login switch set to ON.

  • Any MCS platform APIs endpoints that allow anonymous access. The Analytics Collector, App Policies, Devices, MCS, and Location APIs all have endpoints that can be accessed anonymously. The Database Access API and Notifications API can be accessed from any custom API, including custom APIs that allow anonymous access.

To add an API to a mobile backend with Facebook login:

  1. Make sure that the API allows social login. For custom APIs, you can check by following these steps:

    1. Click side menu icon and select Applications > APIs from the side menu.

    2. Select the API that you want to add and click Open.

    3. In the API Designer, select the Security tab and check the settings.

      Note:

      APIs that you design for use with Facebook login can not be used with other authentication types. If you want an API’s functionality to be available for apps with Facebook login and apps that are based on other types of authentication (such as OAuth, enterprise SSO, or HTTP Basic anonymous access), you need separate variants of the API, each with the appropriate security settings. For more information on API security, see Security in Custom APIs.
  2. Add the API to the mobile backend:

    1. Click side menu icon and select Applications > Mobile Backends from the side menu.

    2. Select your mobile backend and click Open.

    3. In the left navbar of the mobile backend, select APIs.

    4. Click Select APIs.

    5. Click the + (Add) icon for the API.

Getting a Facebook User Access Token Manually

For an app to authenticate through Facebook, it needs to get a user access token from Facebook. Using the MCS client SDK for your platform simplifies this process.

However, if you are testing an API with the API tester or another tool (such as cURL or Postman) or making the REST calls directly from your app, you need to get the user access token yourself. If you are the person who registered the app with Facebook, you can do this by following these steps:

  1. Log into your Facebook account (the one with which you registered the mobile app).

  2. Navigate to https://developers.facebook.com/tools/accesstoken/ and find your app.

  3. Click the You need to grant permissions to your app to get an access token link to generate the token. A token is generated for you on the next page.

Note:

If you anticipate testing the app over a period of several weeks, you might find it convenient to extend the validity of your access token. You can do so by clicking Extend Access Token.

For more information, see Facebook’s documentation on user access tokens at https://developers.facebook.com/docs/facebook-login/access-tokens#usertokens.

Headers Needed for API Calls with Facebook Authentication

When you call custom APIs from apps that use Facebook login, headers need to be passed to handle authentication. If you are using the SDKs for your platform, these headers are constructed for you based on values that you have entered into the SDK’s configuration file.

If you are making REST calls to the APIs directly from your app (or from a separate tool, such as cURL), you need to add the following headers in your calls manually:

  • Authorization: Basic {anonymousKey}

  • Oracle-Mobile-Backend-ID: {mobileBackendID}

  • Oracle-Mobile-Social-Identity-Provider : facebook

  • Oracle-Mobile-Social-Access-Token : {YOUR_FACEBOOK_USER_ACCESS_TOKEN}

Authenticating in Direct REST Calls

When your app uses the MCS client SDK, you store the authentication credentials in one place so that you don’t need to manually insert them into each call. In addition, the SDK handles the encoding of the username and password. However, if you are making the REST calls directly from your app (or you are testing API calls using another tool, such as cURL or Postman), you need to handle the authentication in each call. The value you send in the Authorization header depends on the type of authentication.

Authenticating with OAuth in Direct REST Calls

When you have OAuth enabled as an authentication mechanism for a mobile backend, an app can authenticate itself by sending the mobile backend’s OAuth credentials (client ID and client secret) plus a user name and password to get an OAuth access token. If the API that is being called does not require a logged-in user, then the user name and password are not needed. The app then uses the OAuth token to make REST calls to APIs in the mobile backend.

You need the following information from the Settings page for the mobile backend:

  • OAuth token endpoint

  • Client ID

  • Client secret

If the API is configured to require login, you also need the user name and password for a mobile user.

To construct a REST call to authenticate via OAuth:

  1. Send the request to retrieve an access token:

    1. Base64 encode the clientID:clientSecret string.

    2. Set the Authorization header to Basic client id:client secret-Base64-encoded-string.

    3. Set the Content-Type to application/x-www-form-urlencoded; charset=utf-8.

    4. Set the request body to the appropriate grant type:

      • For access without a logged-in user, use: grant_type=client_credentials

      • For access with a logged-in user, use: grant_type=password&username=username&password=password. The user name and password must be URL encoded.

    5. POST the request to the OAuth token endpoint. For example, in cURL:

      curl -i 
      -H "Authorization: Basic clientId:clientSecret–encoded-string"
      -H "Content-Type: application/x-www-form-urlencoded; charset=utf-8"
      -d "grant_type=client_credentials"
      --request POST oauthTokenEndpoint
  2. In the response, find the access_token property, as shown below (the value is truncated in this example).
    {"oracle_client_assertion_type":"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
    "expires_in":604800,
    "token_type":"Bearer",
    "oracle_tk_context":"client_assertion",
    "access_token":"eyJhbGciOiJ...FIqFiA"} 
  3. Copy the access_token property’s value into the value of the Authorization header.

    The header takes the form Bearer access_token.

Authenticating with HTTP Basic in Direct REST Calls

When you have HTTP Basic enabled as an authentication mechanism for a mobile backend, an app can authenticate itself by sending the mobile backend ID, a user name, and a password. You pass the username and password as a Base64–encoded string. If the API that is being called is set to allow anonymous access, then you pass an anonymous access key instead of a user name and password.

Remember, if your app uses the MCS client SDK, the authentication credentials are stored in one place so you don’t need to manually insert them.

To authenticate with MCS using HTTP Basic, you send a method to any platform endpoint with these headers:
  • Oracle-Mobile-Backend-ID: The mobile backend ID is listed on the Settings tab for the mobile backend.

  • Authorization: Basic: For basic authentication this header should include the mobile user’s name and password encoded in Base64 or the anonymous key. If the anonymous key is available, it will also be displayed on the Settings tab for the mobile backend.

For example:
curl -X GET
     -H "Authorization: Basic {Base64 of mobileUsername:mobileUserPassword} or {anonymousKey}" 
     -H "Oracle-Mobile-Backend-ID: {mobileBackendID}" 
                 {baseUri}/mobile/platform/users/~
For this call, the response would be one of the following:
  • In the case of 200: Success, the payload returned from MCS contains a JSON object with the user information.

  • In case of an error, a JSON error message is returned.

For more information about Base64 encoding, see Base64 Decode and Encode.

How OAuth Works in MCS

This section provides some background on how MCS takes advantage of OAuth. You don’t necessarily need to read this section to do your work, but you might find the conceptual background useful.

OAuth 2.0 is explicitly designed with REST in mind. It supports a variety of different client types that access REST APIs, including mobile apps. Secured APIs are made available only after a mobile app presents a valid OAuth access token.

Oracle Mobile Cloud Service's implementation of OAuth uses a model with the following roles:

  • Resource Owner: The resource owner is responsible for entering credentials to grant authorizations to protected resources. The resource owner is often the app user.

  • Mobile Application: The mobile app is the client that accesses protected resources and makes calls to secure APIs.

  • MCS Server: The MCS server provides the interface for accessing the protected resources.

  • OAuth Server: The OAuth server manages authorizations by the resource owner and issues access tokens. Typically, this role is also handled by the MCS server.

In OAuth 2.0, the client uses an access token issued by the OAuth server to access protected resources hosted by the MCS server.

  1. The mobile app sends credentials to the OAuth server in an HTTP header.

  2. The OAuth server returns an access token.

  3. The mobile app uses the access token to access secure MCS APIs.

This enables MCS to manage permissions and grant applications access to services without requiring a separate login for each individual service. Credentials are issued for each mobile backend. Each mobile app registered with the mobile backend uses those credentials to authenticate with any API associated with that mobile backend.

Before a mobile application can access MCS APIs, it must first register with the MCS OAuth server. The registration is typically a one-time task and can be done when the mobile backend is created. Once registered, the registration remains valid unless revoked. For details on registering a mobile app with a mobile backend, see Registering Applications.

For every custom API in Mobile Cloud Service, the mobile developer decides whether or not authentication is required. This determines which OAuth flow is used.

Resource Owner Password Credentials Grant - Authenticated Access

The resource owner password credentials grant flow is suitable for highly trusted mobile applications because the client could abuse the credentials, or they could unintentionally be disclosed to an attacker. This grant type requires direct access to user credentials, but credentials are used for a single request and are exchanged for an access token. This grant type can eliminate the need for the mobile app to store user credentials for future use, by exchanging them for a long-lived access token or refresh token.

The resource owner password credentials grant flow involves the following steps:

  1. The mobile app prompts the user (resource owner) to enter a username and password.

  2. The mobile app authenticates with the OAuth server through the token endpoint and requests an access token using the credentials entered by the user. The request contains the following parameters:

    • grant_type — Required. Must be set to password.

    • username — Required. The username of the resource owner (user).

    • password — Required. The password of the resource owner (user).

    • scope — Optional. The scope of the authorization.

  3. The OAuth server validates the credentials and issues an access token.

    • access_token

    • token_type

    • expires_in (the number of seconds before the access token is no longer valid; expiration is optional)

  4. The mobile app passes the access token to the MCS service, which validates the token and grants access.

For example, the mobile app makes the following HTTP request using transport-layer security:

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w

After the OAuth server accepts these values, it returns the following response with an access token:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}

Client Credentials Grant - Unauthenticated Access

The client credentials grant flow can be used when the authorization scope is limited to protected resources under the control of the mobile app. A registered trusted app is allowed to obtain an access token by providing only the client credentials to the OAuth server.

This flow is applicable in the following situations:

  • The mobile app is requesting access to protected resources under its control. For example, unauthenticated access to APIs in the Mobile Backend, such as when a mobile banking app retrieves a list of ATMs based on location.

  • The mobile app is requesting access to a protected resource where authorization has been previously arranged with the OAuth server.

The client credentials grant flow involves the following steps:

  1. The mobile app authenticates with the OAuth server through the token endpoint and requests an access token. The request contains the following parameters:

    • grant_type — Required. Must be set to client_credentials.

    • scope — Optional. The scope of the authorization.

  2. The OAuth server validates the credentials and issues an access token.

    The access token has the following parameters:

    • access_token

    • token_type

    • expires_in (the number of seconds before the access token is no longer valid; expiration is optional)

  3. The mobile app passes the access token to the service. The service accepts the token and allows access.

For example, the mobile app makes the following HTTP request using transport-layer security

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials

The OAuth server MUST authenticate the client. It returns the following response with an access token:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"example_parameter":"example_value"
}

Securing Cross-Site Requests to MCS APIs

In addition to setting authentication methods, it’s very important that you manage cross-origin resource sharing (CORS) for access to MCS APIs. You do so through the Security_AllowOrigin environment policy.

For browser-based applications, particularly those that use Single-Sign On (SSO) authentication, you should either not allow cross-site access at all or restrict access only to trusted origins where authorized applications are known to be hosted to mitigate vulnerability to Cross-Site Request Forgery (CSRF) attacks. If you're not using browser-based applications, it’s best to use the default value, disallow, for Security_AllowOrigin.

Control cross-site access by setting the Security_AllowOrigin environment policy value to either disallow (the default value) or to a comma separated list of URL patterns, which specifies a whitelist of trusted URLs from which cross-site requests can be made. If the origin of a cross-site request matches at least one of the patterns in the whitelist, the request is allowed.

For example, the URL value for Security_AllowOrigin might look like this:

https://myexample.com, https://*.example.com, https://*.example2.com

When specifying a URL, note the following:

  • You must include the port, unless you are using the default port for the URL scheme. For example, the pattern http://www.example.com matches the URL http://www.example.com or the URL http://www.example.com:80, but not http://www.example.com:8080.

  • When specifying values for Security_AllowOrigin, don’t include path parts and don’t include a trailing forward slash, ‘/’, character. For example, the pattern http://www.example.com/ won’t match http://www.example.com.

  • You can use an asterisk (*) as a wildcard character within a URL segment but it doesn't apply across dot (.), forward slash (/), or colon (:) characters.

    For example, if the URL is https://example.example.com:8080, the following patterns match:

    • https://*.example.com:8080

    • https://*.example.com:*

    • https://ex*.example.com:*

    These patterns, however, won’t match:

    • https://*.example.com*

    • https://example*.oracle.com:*

    These restrictions are designed to prevent matching unintended sites.

Note:

For convenience, during the development of a browser-based application or during testing of a hybrid application running in the browser, you can set Security_AllowOrigin to http://localhost:[port], but be sure to update the value in production.