Skip to content

Enabling Client Registrations

Client Registrations

In certain cases, such as when Download Tracking is enabled, the OData service needs to track registered clients. For this purpose, the CSDL must contain a ClientRegistration entity type and corresponding ClientRegistrationSet entity set.

The ClientRegistration entity type:

  • Must include a ClientID key property of type Edm.Int64

  • Must include a ClientGUID property of type Edm.Guid

  • May include an AuthorizedUser property of type Edm.String. If specified, this property will be populated automatically with the registration's authorized user name if the OData service is deployed with authentication enabled. Otherwise this property will be null.

  • May include arbitrary other properties of use to the client application.

Example:

<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://docs.oasis-open.org/odata/ns/edmx http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edmx.xsd http://docs.oasis-open.org/odata/ns/edm http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edm.xsd">
    ...
    <edmx:DataServices>
        <Schema Namespace="my.schema" Alias="Self" xmlns="http://docs.oasis-open.org/odata/ns/edm">
            ...
            <EntityType Name="ClientRegistration">
                <Key>
                    <PropertyRef Name="ClientID"/>
                </Key>
                <Property Name="ClientID" Type="Edm.Int64" Nullable="false"/>
                <Property Name="ClientGUID" Type="Edm.Guid" Nullable="false"/>
                <Property Name="AuthorizedUser" Type="Edm.String" Nullable="true" MaxLength="200"/>
            </EntityType>
            <EntityContainer Name="MyService">
                ...
                <EntitySet Name="ClientRegistrationSet" EntityType="Self.ClientRegistration"/>
            </EntityContainer>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

Client Credentials

Properties such as passwords, or other security credentials apart from AuthorizedUser, should not be stored in the ClientRegistration entity type. Instead, the CSDL should contain a ClientCredentials entity type and corresponding ClientCredentialsSet entity set.

Example:

<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://docs.oasis-open.org/odata/ns/edmx http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edmx.xsd http://docs.oasis-open.org/odata/ns/edm http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edm.xsd">
    ...
    <edmx:DataServices>
        <Schema Namespace="my.schema" Alias="Self" xmlns="http://docs.oasis-open.org/odata/ns/edm">
            ...
            <EntityType Name="ClientCredentials">
                <Key>
                    <PropertyRef Name="ClientID"/>
                </Key>
                <Property Name="ClientID" Type="Edm.Int64" Nullable="false"/>
                <Property Name="BackendUsername" Type="Edm.String" Nullable="true" MaxLength="200"/>
                <Property Name="BackendPassword" Type="Edm.String" Nullable="true" MaxLength="200"/>
            </EntityType>
            <EntityContainer Name="MyService">
                ...
                <EntitySet Name="ClientCredentialsSet" EntityType="Self.ClientCredentials"/>
            </EntityContainer>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

Client credentials should be stored in secure client-side storage, preferably encrypted by an application passcode or similar mechanism. Any attempt to upload client credentials to the server, by POSTing to the ClientCredentialsSet entity set for example, will be rejected with response status code 405 (Method Not Allowed).

To enable the server to access the client credentials when needed, without having to persist them in the server's database, every request from a client application to an OData service with a ClientCredentials entity type should be accompanied by an X-Client-Credentials HTTP request header, where the header value contains the credentials entity encoded as a JSON object within a data URI, using media type application/json and Base64-encoded data. To facilitate this encoding of credentials, see ToJSON.dataURI and HttpHeaders.withData in the client SDK documentation, or refer to the following example showing the encoding steps.

Example encoding of credentials entity with Username of secretuser and Password of secretpass:

  • JSON-encoded entity: {"Username":"secretuser","Password":"secretpass"}
  • Base64-encoded JSON: eyJVc2VybmFtZSI6InNlY3JldHVzZXIiLCJQYXNzd29yZCI6InNlY3JldHBhc3MifQ==
  • Encoded as data URI: data:application/json;base64,eyJVc2VybmFtZSI6InNlY3JldHVzZXIiLCJQYXNzd29yZCI6InNlY3JldHBhc3MifQ==
  • HTTP header: X-Client-Credentials: data:application/json;base64,eyJVc2VybmFtZSI6InNlY3JldHVzZXIiLCJQYXNzd29yZCI6InNlY3JldHBhc3MifQ==

When you use the SAP BTP SDK for Android or iOS to build a client application, specify the values for headers such as X-Client-Credentials in the customHeaders property of the OfflineODataParameters object, which is passed to the constructor/initializer of OfflineODataProvider. The Android com.sap.cloud.mobile.foundation.securestore.SecureKeyValueStore and iOS Keychain Services APIs are recommended for storing client credentials across application restarts.

Registration Header

Every client request from a client application to an OData service with client registrations should be accompanied by a Client-Instance-ID HTTP request header, which uniquely identifies a particular instance of the client application on a particular client computer. The header value should be in 36-character UUID format, preferably a Version 4 (random) variant.

When a client uses HTTP POST to the ClientRegistrationSet entity set to create a registration with the server, the Client-Instance-ID header value is copied into the ClientGUID property of the newly created ClientRegistration entity, and a corresponding ClientID property is automatically generated by the server. The ClientID can be considered a short form of the ClientGUID, and is used by the server to associate any client-specific information with the registration, such as download tracking data or client identifiers for filter entities.

When you build client applications using the SAP BTP SDK for Android or iOS, you can specify values for headers such as Client-Instance-ID in the customHeaders property of the OfflineODataParameters object that is passed to the constructor/initializer of OfflineODataProvider. The client application should use the same Client-Instance-ID value across application restarts (unless the client database is recreated, in which case a new Client-Instance-ID should be used). An application-specific local file can be used for storing Client-Instance-ID values across application restarts.

Recent versions of the client SDKs have an autoRegisterClient property in the OfflineODataParameters class, which can simplify the process of obtaining and storing the necessary client registration.

Registration Expiry

Inactive client registrations are automatically deleted after 49 days (by default). The expiry interval for inactive registrations is one day less than the retainDeletionsFor property of the SQLDatabaseProvider class in the Server OData API. You can modify this property by editing the generated ProviderSettings class and rebuilding/redeploying the generated service.

The rationale for deferred expiration is as follows. Whenever data is to be deleted from the database, it is marked as logically deleted rather than being immediately physically deleted from the database. This allows for a client to be offline for an extended period, then come back online and execute delta queries to discover deletions (and other changes) that occurred while the client was offline. If the client was permitted to remain offline for longer than the deletion retention period, then, when the client comes online again to execute delta queries, it might fail to be notified of some deletions that occurred while it was offline. By forcing an inactive client's registration to expire one day before the deletion retention period, it can be ensured that the client will always be able either to successfully download all changes (including deletions) that occurred while the client was offline, or to be notified that the client's registration has expired.


Last update: July 11, 2022