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.
class MyTokenSigner implements TokenSigner {
/**
* 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 = new NetworkManager();
@NotNull
@Override
public void sign(@NotNull String unsignedToken, @NotNull ResultCallback<String> callback) {
network.post("https://www.example.com/sign", body: unsignedToken.getBytes("UTF-8"), new NetworkListener() {
/**
* Send a result success if the data received is formatted as expected.
*
* @param bytes The body of the response.
*/
@NotNull
@Override
void success(byte[] bytes) {
String signedToken = new String(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
@Override
void failure(Throwable t) {
Result<String> result = Result.Companion.FAILURE(t);
resultCallback.execute(result);
}
});
}
}
Swift
class MyTokenSigner: TokenSigner {
struct SigningError: Error {
let message: String
}
let signingURL = URL(string: "http://{BACKEND-SIGNING-URL}")!
func sign(_ 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 in
guard let response = response as? HTTPURLResponse else {
// send a failure result
resultHandler(.failure(SigningError(message: "Invalid response type, expecting HTTPURLResponse")))
}
guard response.statusCode == 200 else {
// send a failure result
resultHandler(.failure(SigningError(message: "Bad response: \(response.statusCode)")))
return
}
guard let data = data, let signedToken = String(data: data, encoding: .utf8) else {
// Send a failure result
resultHandler(.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.
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.
Response
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI2M2Q5YTM4OS00ZGRjLTRkZjEtOGRkMS1hZjZhMTBjNzIyNmUiLCJzdWIiOiIxNCIsImp0aSI6IkJEOTg4QjJFLUIxNkEtNDlCOC04ODgyLTlCM0M5RDM1REQ4NCIsIm5iZiI6MTQ5NzU3NzM4MSwiZXhwIjoxNDk3NTc4MjgxfQ.HOST-BACKEND-SIGNATURE
IMPORTANT: The header and payload must not be modified in any way. The response body is the prototype token with the signature appended, as shown.