This document assumes there is an enrolled and active user created on the host app's DriveSync� server using the Enrolment API or through Business Center. Interacting with the IMS Enrolment API and Business Center is out of the scope of this document. If you have questions about the product please contact us.
Mobile App Signing Interface
IMS SDK validates the identity of actively enrolled users via JSON Web Tokens. The host app is responsible for providing the SDK with a TokenSigner object that will make a request to the host's back end. The successful network response will provide a signed JWT, which is then provided back to the SDK.
The SDK will use the TokenSigner by providing it with an unsigned JWT prototype; e.g. a JWT with a header and payload only. The TokenSigner will provide a signed JWT to the SDK via a callback. Upon reception of the signed JWT, the SDK will verify that all the required fields are provided in the JWT (see in code documentation for more details) before using it to make network calls to the IMS back end.
// header{"alg":"RS256","typ":"JWT"}// payload{"iss":"63d9a389-4ddc-4df1-8dd1-af6a10c7226e","sub":"14","jti":"BD988B2E-B16A-49B8-8882-9B3C9D35DD84","nbf":1497577381,"exp":1497578281}// Encoded Unsigned JWT provided to `TokenSigner` by the SDKeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI2M2Q5YTM4OS00ZGRjLTRkZjEtOGRkMS1hZjZhMTBjNzIyNmUiLCJzdWIiOiIxNCIsImp0aSI6IkJEOTg4QjJFLUIxNkEtNDlCOC04ODgyLTlCM0M5RDM1REQ4NCIsIm5iZiI6MTQ5NzU3NzM4MSwiZXhwIjoxNDk3NTc4MjgxfQ
NOTE: The window of time a JWT is valid can be no longer than 15 minutes. i.e. exp - nbf <= 15 minutes
Token Signer
As stated previously, the host app must provide the SDK with an object that conforms to the TokenSigner protocol/interface to sign tokens.
classMyTokenSignerimplementsTokenSigner { /** * Note: `NetworkManager` is meant to be a representation of an asynchronous * network class and is not provided as part of the SDK. It is a reference only. */NetworkManager network =newNetworkManager(); @NotNull @Overridepublicvoidsign(@NotNullString unsignedToken, @NotNullResultCallback<String> callback) {network.post("https://www.example.com/sign", body:unsignedToken.getBytes("UTF-8"),newNetworkListener() { /** * Send a result success if the data received is formatted as expected. * * @param bytes The body of the response. */ @NotNull @Overridevoidsuccess(byte[] bytes) {String signedToken =newString(bytes,"UTF-8");Result<String> result =Result.Companion.SUCCESS(signedToken);callback.execute(result); } /** * Send a result failure if there was a problem. * * @param t The reason for the failure. */ @NotNull @Overridevoidfailure(Throwable t) {Result<String> result =Result.Companion.FAILURE(t);resultCallback.execute(result); } }); }}
Swift
classMyTokenSigner:TokenSigner {structSigningError:Error{let message: String }let signingURL =URL(string:"http://{BACKEND-SIGNING-URL}")!funcsign(_unsignedToken: String, resultHandler: @escaping ResultHandler<String>) {var request =URLRequest(url: signingURL) request.httpMethod ="POST" request.httpBody = unsignedToken.data(using: .utf8) request.allHTTPHeaderFields = ["Authorization":"Bearer {APP-AUTHORIZATION}","Content-Type":"text/plain" ]let task = URLSession.shared.dataTask(with: request) { data, response, error inguardlet response = response as? HTTPURLResponse else {// send a failure resultresultHandler(.failure(SigningError(message:"Invalid response type, expecting HTTPURLResponse"))) }guard response.statusCode ==200else {// send a failure resultresultHandler(.failure(SigningError(message:"Bad response: \(response.statusCode)")))return }guardlet data = data, let signedToken =String(data: data, encoding: .utf8)else {// Send a failure resultresultHandler(.failure(SigningError(message:"Problem signing token")))return }// Send a success result if the data received is formatted as expected.resultHandler(.success(signedToken)) } task.resume() }}
iOS TokenSigner Initialization
The SDK receives the TokenSigner via a factory that is provided during the SDK initialization process. The SDK initialization must occur at the beginning of the host app's lifecycle before any other SDK functionality is invoked. You can see an example of the full initialization in the usage section of this document.
Swift
// Somewhere early in the app lifecycle...initialize(/* other initializations... */, tokenSignerFactory: { MyTokenSigner() })
Android TokenSigner Configuration
The SDK receives the TokenSignerclass during the SDK configuration process. The token signer class must have a no-argument (empty) constructor, and must not be obfuscated. You can see an example in theInitialize the SDK section of this document.
if (!ImsSdkManager.isConfigured) { ImsSdkManager.setSdkConfiguration( context, ImsSdkManager.Builder()// Token signer class MUST have a no-argument constructor .setTokenSigner(MyTokenSigner::class.java)// Other configuration options .build() )}
Signing Security Requirements
The following are security requirements for the host app to follow when signing tokens:
For additional security, please consider the following procedures:
Public Certificate and RSA Key Pair
The host is responsible for generating a 2048 bit RSA key pair and providing IMS with a public certificate generated from the key pair, signed using the SHA-256 with RSA algorithm. The generated private key should be used to sign the JWT prototypes.
Certificate Example
This is an example of a public certificate generated from a key pair that could be provided to IMS for JWT validation.
TIP: The private/public key pair can be generated using a command line tool such as Java Keystore or any other tool that can generate the appropriate key pair and certificate.
Example HTTP Signing Request This is an example request to the host app's back end, requesting that an unsigned JWT prototype be validated and signed. This is only an example implementation. The actual implementation is left up to the host app, provided the requirements outlined above are followed.
Request
POST /sign HTTP/1.1Host:www.example.comAuthorization:Bearer CLIENT_AUTHORIZATION_TOKENContent-Type:text/plainCache-Control:no-cacheeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI2M2Q5YTM4OS00ZGRjLTRkZjEtOGRkMS1hZjZhMTBjNzIyNmUiLCJzdWIiOiIxNCIsImp0aSI6IkJEOTg4QjJFLUIxNkEtNDlCOC04ODgyLTlCM0M5RDM1REQ4NCIsIm5iZiI6MTQ5NzU3NzM4MSwiZXhwIjoxNDk3NTc4MjgxfQ
The bearer token (CLIENT_AUTHORIZATION_TOKEN) in the above request is an example of an authentication token used by the app and the host's back end, not the SDK JWT. This token is used to determine the authenticity of the host's user.
The body of the request is the JWT Prototype created by IMS SDK.