README.md 21.8 KB
Newer Older
Jonas Passerini's avatar
Jonas Passerini committed
1
2
3
4
5
6
7
## Summary

This is the Android SDK of Futurae. You can read more about Futurae™ at [futurae.com].

## Table of contents

* [Basic integration](#basic-integration)
Claudio Marforio's avatar
Claudio Marforio committed
8
9
   * [Get FuturaeKit SDK for Android via Maven](#get-futuraekit-sdk-for-android-via-maven)
   * [Get FuturaeKit SDK for Android Manually](#get-futuraekit-sdk-for-android-manually)
Jonas Passerini's avatar
Jonas Passerini committed
10
11
12
   * [Add permissions](#add-permissions)
   * [Basic setup](#basic-setup)
   * [Build your app](#build-your-app)
Claudio Marforio's avatar
Claudio Marforio committed
13
   * [R8 / Proguard](#r8-proguard)
Jonas Passerini's avatar
Jonas Passerini committed
14
15
16
17
* [Features](#features)
   * [Callbacks](#callbacks)
   * [URI Schemes](#uri-schemes)
   * [Push Notifications](#push-notifications)
18
19
      * [FCM Token Registration](#fcm-token-registration)
      * [FCM Listener Service](#fcm-listener-service)
Jonas Passerini's avatar
Jonas Passerini committed
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
			* [Local Intents](#local-intents)
   * [Enroll User](#enroll-user)
   * [Logout User](#logout-user)
   * [Account Status](#account-status)
   * [Authenticate User](#authenticate-user)
      * [QR Code Factor](#qr-code-factor)
      * [Push Notification Factor](#push-notification-factor)
         * [Approve Authentication](#approve-authentication)
         * [Reject Authentication](#reject-authentication)
      * [TOTP Factor](#totp-factor)
      * [Session Information](#session-information)


## <a id="basic-integration" />Basic integration
We will describe the steps to integrate the FuturaeKit SDK into your Android project. We are going to assume that you are using Android Studio for your development.

Claudio Marforio's avatar
Claudio Marforio committed
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
### <a id="get-futuraekit-sdk-for-android-via-maven" />Get FuturaeKit SDK for Android via Maven
The *preferred* way to get the FuturaeKit SDK fro Android is through maven and the Futurae private repository.

To do so add the following lines to your `build.gradle` file:

```
repositories {
  maven {
    url "https://artifactory.futurae.com/artifactory/futurae-mobile"
    credentials {
      username = "anonymous"
      password = ""
    }
  }
}

dependencies {
  implementation('com.futurae.sdk:futuraekit:1.0.0')
}
```
Jonas Passerini's avatar
Jonas Passerini committed
56

Claudio Marforio's avatar
Claudio Marforio committed
57
58
59
60
61
Of course, make sure to specify the correct version number.

### <a id="get-futuraekit-sdk-for-android-via-maven" />Get FuturaeKit SDK for Android Manually
Alternatively, *although discouraged*, you can download the latest SDK from the [releases](https://git.futurae.com/futurae-public/futurae-android-sdk/tags), or clone this repository directly.
This repository also contains a simple demo app to show how the SDK can be integrated.
Jonas Passerini's avatar
Jonas Passerini committed
62
63
64
65

To integrate the FuturaeKit SDK into your project, copy `futuraekit.aar` into the `src/main/libs` folder of your app.
Then, in your modules `build.gradle` (the one under "app"), add the following dependencies:
```
Claudio Marforio's avatar
Claudio Marforio committed
66
67
68
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.3.0'
implementation 'com.squareup.moshi:moshi-adapters:1.4.0'
69
implementation 'com.squareup.okhttp3:okhttp:3.8.0'
Claudio Marforio's avatar
Claudio Marforio committed
70
71
72
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0'
implementation 'com.github.nisrulz:easydeviceinfo-base:2.4.1'
implementation files('src/main/libs/futuraekit.aar')
Jonas Passerini's avatar
Jonas Passerini committed
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
```

![][gradle-app]

And in the projects `build.gradle` adjust the repositories to include the `libs` folder:
```
allprojects {
    repositories {
        google()
        jcenter()
        flatDir {
            dirs 'src/main/libs'
        }
    }
}
```

![][gradle-project]


### <a id="add-permissions" />Add permissions
Please add the following permissions, which the FuturaeKit SDK needs, if they are not already present in your AndroidManifest.xml file:

```
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />

<meta-data
        android:name="com.google.android.gms.vision.DEPENDENCIES"
        android:value="barcode"/>
```


### <a id="basic-setup" />Basic setup
We recommend using an android [Application][android_application] class to initialize the SDK. If you already have one in your app already, follow these steps:

Firstly, in your `Application` class find or create the `onCreate` method and add the following code to initialize the FuturaeKit SDK:

```java
import com.futurae.sdk.FuturaeClient;

public class AppMain extends Application {

    // overrides
    @Override
    public final void onCreate() {

        super.onCreate();

        FuturaeClient.launch(this);
    }
}
```


Secondly, in your `res/values` folder make sure to create a file `futurae.xml` with the following contents:

```xml
<?xml version="1.0" encoding="utf-8"?>
<resources>

137
138
    <string name="ftr_sdk_id">{FuturaeSdkId}</string>
    <string name="ftr_sdk_key">{FuturaeSdkKey}</string>
Jonas Passerini's avatar
Jonas Passerini committed
139
140
141
142
143
    <string name="ftr_base_url">https://api.futurae.com:443</string>

</resources>
```

144
**Note**: Initializing the FuturaeKit SDK like this is `very important`. Replace `{FuturaeSdkId}` and `{FuturaeSdkKey}` with your SDK ID and key.
Jonas Passerini's avatar
Jonas Passerini committed
145
146
147
148
149

### <a id="build-your-app" />Build your app

Build and run your app. If the build succeeds, you should carefully read the SDK logs in the console.

Claudio Marforio's avatar
Claudio Marforio committed
150
151
152
153
154
155

### <a id="r8-proguard" />R8 / ProGuard

If you are using R8 or ProGuard add the options from [build.gradle][build_gradle].


Jonas Passerini's avatar
Jonas Passerini committed
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
## <a id="features" />Features
### <a id="callbacks" />Callbacks
The SDK methods that perform API calls use callbacks as the feedback mechanism. These calls expect an object of the `FuturaeCallback` interface as an argument:
```java
public interface FuturaeCallback {
    void success();
    void failure(Throwable throwable);
}
```

### <a id="uri-schemes" />URI Schemes
The SDK is able to handle URI scheme calls, which can be used to either **enroll** or **authenticate** users.
Once your activity has been set up to handle the URI scheme call intents, get the intent data in the `onCreate()` method of your activity, which contains the URI that should be passed in the SDK, using the `handleUri()` method:

```java
FuturaeClient.sharedClient().handleUri(uriString, new FuturaeCallback() {
	@Override
	public void success() {

	}

	@Override
	public void failure(Throwable throwable) {

	}
});
```

Claudio Marforio's avatar
Claudio Marforio committed
184
185
**Note**: In case you attempt an authentication with a URI scheme call, and this authentication includes extra information to be displayed to the user, you must retrieve this information from the server and include it in the authentication response; see section [Session Information](#session-information) for details on how to do that.

Jonas Passerini's avatar
Jonas Passerini committed
186
### <a id="push-notifications" />Push Notifications
187
Your app must be set up to receive Firebase Cloud Messaging (FCM) push notifications from our server. You can choose to receive and handle these notifications yourself, or alternatively you can use the existing infrastructure provided in the SDK. You can find more information on how to setup FCM push notifications for your app in the [Firebase Cloud Messaging Developer Guide](https://firebase.google.com/docs/cloud-messaging/).
Jonas Passerini's avatar
Jonas Passerini committed
188

189
In order to be able to receive FCM notifications, you need to specify the Firebase Messaging service inside the application section of your Manifest:
Jonas Passerini's avatar
Jonas Passerini committed
190
```xml
191
192
193
194
195
<service android:name="com.futurae.sdk.messaging.FTRFcmMessagingService">
	<intent-filter>
		<action android:name="com.google.firebase.MESSAGING_EVENT" />
	</intent-filter>
</service>
Jonas Passerini's avatar
Jonas Passerini committed
196
197
```

198
199
200
201
For this purpose, you can either use the one included in the SDK (`com.futurae.sdk.messaging.FTRFcmMessagingService`), or write your own. This service overrides two important methods:
```java
    @Override
    public void onNewToken(String token);
Jonas Passerini's avatar
Jonas Passerini committed
202

203
204
    @Override
    public void onMessageReceived(RemoteMessage message);
Jonas Passerini's avatar
Jonas Passerini committed
205
206
```

207
The first one is invoked whenever a new FCM push token has been generated for the app; it is important to register this token with the Futurae backend in order to continue receiving push notifications. The `FTRFcmMessagingService` implements this functionality.
Jonas Passerini's avatar
Jonas Passerini committed
208

209
210
211
212
The second one is invoked whenever a new push notification (or cloud message) is received by the app. The `FTRFcmMessagingService` then processes this message and invokes the SDK accordingly.

#### <a id="fcm-token-registration" />FCM Token Registration
The `FTRFcmMessagingService` is responsible for registering the app's FCM token to the Futurae server. This is important for the server to be able to issue FCM notifications for your app. The provided service handles this, however if you need to, you can write your own or extend the existing one.
213

214
If you are implementing **your own FCM notification handling**, you should register the FCM token to the Futurae server every time it changes. The call that registers the FCM token to the Futurae server is `registerPushToken()`, and it is necessary every time the FCM token is generated or is changed by FCM.
Jonas Passerini's avatar
Jonas Passerini committed
215

216
For example, once the app receives a new FCM token (e.g. via an `onNewToken()` callback in your own `FirebaseMessagingService` subclass), the token needs to be obtained and registered to the Futurae server using the following code:
Jonas Passerini's avatar
Jonas Passerini committed
217
```java
218
FuturaeClient.sharedClient().registerPushToken(fcmToken, new FuturaeCallback() {
Jonas Passerini's avatar
Jonas Passerini committed
219
220
221
222
223
224
225
226
227
228
229
230
	@Override
	public void success() {

	}

	@Override
	public void failure(Throwable t) {

	}
});
```

231
232
#### <a id="fcm-listener-service" />FCM Listener Service
The `FTRFcmMessagingService` receives FCM push notifications and handles them, according to the actions dictated by the Futurae server. You can use or extend the service provided by the SDK, or write your own. There are two distinct push notification types issued by the Futurae server: **Aprove** or **Unenroll**.
Jonas Passerini's avatar
Jonas Passerini committed
233

234
In case you want to process and handle the FCM notifications without using `FTRFcmMessagingService`, you must use the following code in order to process and handle the notifications sent by the Futurae server, inside the implementation of your own `FirebaseMessagingService` subclass:
Jonas Passerini's avatar
Jonas Passerini committed
235
236
```java
@Override
237
public void onMessageReceived(RemoteMessage message) {
Jonas Passerini's avatar
Jonas Passerini committed
238

239
240
	// Create and handle a Futurae notification, containing a Bundle with any data from message.getData()
	FTRNotification notification = notificationFactory.createNotification(service, data);
Jonas Passerini's avatar
Jonas Passerini committed
241
242
243
244
245
	notification.handle();
}
```

#### <a id="local-intents" />Local Intents
246
247
Once a Futurae FCM notification has been handled, the SDK will notify the host app using **local broadcasts**. The app should register a broadcast receiver for these intents and react accordingly. There are three distinct Intents that the notification handlers might send in a local broadcast:
* `INTENT_GENERIC_NOTIFICATION_ERROR`: Indicates that an error was encountered during the processing or handling of a FCM notification.
Jonas Passerini's avatar
Jonas Passerini committed
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
* `INTENT_APPROVE_AUTH_MESSAGE`: Indicates that a Push Notification Authentication has been initiated.
* `INTENT_ACCOUNT_UNENROLL_MESSAGE`: Indicates that a user account has been logged out remotely.

The following example shows how to register for these intents:
```java
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Shared.INTENT_GENERIC_NOTIFICATION_ERROR);  // General notification error intent
intentFilter.addAction(Shared.INTENT_APPROVE_AUTH_MESSAGE);        // Approve Authentication notification intent
intentFilter.addAction(Shared.INTENT_ACCOUNT_UNENROLL_MESSAGE);    // Logout user notification intent

LocalBroadcastManager.getInstance(getContext()).registerReceiver(new BroadcastReceiver() {

	@Override
	public void onReceive(Context context, Intent intent) {

		switch(intent.getAction()) {
			case Shared.INTENT_ACCOUNT_UNENROLL_MESSAGE:
				// Handle unenroll notification (e.g. refresh lists)
				break;

			case Shared.INTENT_APPROVE_AUTH_MESSAGE:
				// Handle approve notification (e.g. show approve view)
				break;

			case Shared.INTENT_GENERIC_NOTIFICATION_ERROR:
273
				// Handle FCM notification error
Jonas Passerini's avatar
Jonas Passerini committed
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
				break;
		}
	}
}, intentFilter);
```

### <a id="enroll-user" />Enroll User

To enroll a user, you must call the `enroll()` method, using a valid code obtained by scanning an enrolment QR Code. For example, you can use a QR Code Reader Activity to scan a code and obtain the result:
```java
startActivityForResult(FTRQRCodeActivity.getIntent(this), FTRQRCodeActivity.RESULT_BARCODE);
```

If a QR Code is successfully scanned then `onActivityResult` will be called, with the scanned code:
```java
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

	if (resultCode == RESULT_OK && requestCode == FTRQRCodeActivity.RESULT_BARCODE) {
		Barcode qrcode = data.getParcelableExtra(FTRQRCodeActivity.PARAM_BARCODE);

		FuturaeClient.sharedClient().enroll(qrcode.rawValue, new FuturaeCallback() {
			@Override
			public void success() {

			}

			@Override
			public void failure(Throwable throwable) {

			}
		});
	}

}
```

Please make sure to call enroll, inside the onActivityResult method to complete the user enrollment.

### <a id="logout-user" />Logout User
To remove a user account from the app and the SDK, call the `logout()` method:
```java
FuturaeClient.sharedClient().logout(userId, new FuturaeCallback() {
	@Override
	public void success() {

	}

	@Override
	public void failure(Throwable throwable) {

	}
});
```

329
Typically this should happen either when the user removes the account manually from the app, or when a user has been logged out remotely by the server. In the former case, calling the `logout()` method is enough, as it notifies the server of the logout and deletes the account from the SDK too. In the latter case, the server will send a FCM notification to the app, and the default handler of the notification will delete the account from the SDK as well. In this case, the notification handler will also send a local broadcast to the app (see `INTENT_ACCOUNT_UNENROLL_MESSAGE` [above](#local-intents), so that the app can also perform any further action required (e.g. refresh the list of active accounts in an account view).
Jonas Passerini's avatar
Jonas Passerini committed
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381

The intent contains the User ID as an extra:
```java
String userId = intent.getStringExtra(FTRUnenrollNotification.PARAM_USER_ID);
```

### <a id="account-status" />Account Status
To get a list of all enrolled accounts, call the following method:

```java
List<Account> accounts = FuturaeClient.sharedClient().getAccounts();
```

To fetch the status and current sessions for these accounts, you can use the following method (where `userIds` is a list of the corresponding user IDs):

```java
FuturaeClient.sharedClient().getAccountsStatus(userIds, new FuturaeResultCallback<AccountsStatus>() {
    @Override
    public void success(AccountsStatus accountsStatus) {
        // Handle the pending sessions
    }

    @Override
    public void failure(Throwable throwable) {
        // Handle the error
    }
});
```

**Hint:** You can use this method if you want to check if there are any pending sessions, e.g. when the app wakes up or the user refreshes the view.
For each account, a list of active sessions will be returned, and each session includes a `session ID` to proceed with the authentication.


### <a id="auth-user" />Authenticate User
To authenticate (or reject) a user session, depending on the authentication factor, you can use the following methods: **QR Code Factor**, or **Push Notification Factor**.

#### <a id="qrcode-auth" />QR Code Factor
To authenticate with the QR Code Factor, scan the QR Code provided by the server and pass its contents to the following method:
```java
FuturaeClient.sharedClient().approveAuth(qrCodeString, new FuturaeCallback() {
	@Override
	public void success() {

	}

	@Override
	public void failure(Throwable throwable) {

	}
});
```

Claudio Marforio's avatar
Claudio Marforio committed
382
383
**Note**: In case you attempt an authentication with a QR Code, and this authentication includes extra information to be displayed to the user, you must retrieve this information from the server and include it in the authentication response; see section [Session Information](#session-information) for details on how to do that.

Jonas Passerini's avatar
Jonas Passerini committed
384
385
386
387
388
389
390
391
392
393
394
395
#### <a id="approve-auth" />Push Notification Factor
When a Push Notification Factor session is initiated on the server side, the server will send a push notification to the app, where the user should approve or reject the authentication session. The notification is received and handled by the SDK, which in turn will send a local broadcast (see `INTENT_APPROVE_AUTH_MESSAGE` [above](#local-intents)), so that the app can perform any required actions. For example, the app might want to display a prompt to the user so that they can approve or reject the session.

The intent contains an object that describes the authentication session as an extra. This object contains the User ID and the Session ID, which are required for sending the authentication outcome to the server:
```java
ApproveSession authSession = intent.getParcelableExtra(FTRApproveNotification.PARAM_APPROVE_SESSION);
String userId = authSession.getUserId();
String sessionId = authSession.getSessionId();
```

Once the outcome of the authentication has been decided by the app, it should be sent to the server for the authentication session to complete.

Claudio Marforio's avatar
Claudio Marforio committed
396
397
**Note**: In case you attempt an authentication via push notification, and this authentication includes extra information to be displayed to the user, you must retrieve this information from the server and include it in the authentication response; see section [Session Information](#session-information) for details on how to do that.

Jonas Passerini's avatar
Jonas Passerini committed
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
##### <a id="approve-reply" />Approve Authentication
To approve the authentication session, use the following method:
```java
FuturaeClient.sharedClient().approveAuth(userId, sessionId, new FuturaeCallback() {
	@Override
	public void success() {

	}

	@Override
	public void failure(Throwable t) {

	}
});
```

##### <a id="reject-reply" />Reject Authentication
The user might choose to reject the authentication session. Additionally, in case the session has not been initiated by the user, they might also choose to report a fraudulent authentication attempt back to the server. In this case, use the following method:
```java
boolean reportFraud = false; // Set to true to report a fraudulent attempt
FuturaeClient.sharedClient().rejectAuth(userId, sessionId, reportFraud, new FuturaeCallback() {
	@Override
	public void success() {

	}

	@Override
	public void failure(Throwable t) {

	}
});
```

#### <a id="totp-auth" />TOTP Factor
The TOTP Factor can be used for offline authentication, as there is no requirement for an internet connection in the app. To get the current TOTP generated by the SDK for a specific user account, call the following method:
```java
CurrentTotp totp = FuturaeClient.sharedClient().nextTotp(userId);
Claudio Marforio's avatar
Claudio Marforio committed
435
436
String passcode = totp.getPasscode();            // The TOTP that the user should use to authenticate
int remainingSeconds = totp.getRemainingSecs();  // The remaining seconds of validity of this TOTP
Jonas Passerini's avatar
Jonas Passerini committed
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
```
As seen in this example, the `nextTotp()` method returns an object that contains the TOTP itself, but also the remaining seconds that this TOTP will be still valid for. After this time, a new TOTP must be obtained by the SDK.


#### <a id="session-information" />Session Information
For a given session, either identified via a `session ID` (e.g. received by a push notification) or a `session Token` (e.g. received by a QRCode scan), you can ask the server for more information about the session:

```java
// if you have a session ID
FuturaeClient.sharedClient().sessionInfoById(userId, sessionId, new FuturaeResultCallback<SessionInfo>() {
    @Override
    public void success(SessionInfo sessionInfo) {
        // Handle the session
    }

    @Override
    public void failure(Throwable throwable) {
        // Handle the error
    }
});

// if you have a session Token
Nikos Karapanos's avatar
Nikos Karapanos committed
459
FuturaeClient.sharedClient().sessionInfoByToken(userId, sessionId, new FuturaeResultCallback<SessionInfo>() {
Jonas Passerini's avatar
Jonas Passerini committed
460
461
462
463
464
465
466
467
468
469
470
471
472
473
    @Override
    public void success(SessionInfo sessionInfo) {
        // Handle the session
    }

    @Override
    public void failure(Throwable throwable) {
        // Handle the error
    }
});
```

If there is extra information to be displayed to the user, for example when confirming a transaction, this will be indicated with a list of key-value pairs in the `extra_info` part of the response.

Claudio Marforio's avatar
Claudio Marforio committed
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
In order to query the server for the session information, you need the user ID and the session ID or token. You can use the following helper methods to obtain these from either a URI or a QR Code:
```java
public class FuturaeClient {
    public static String getUserIdFromQrcode(String qrCode);
    public static String getSessionTokenFromQrcode(String qrCode);
    public static String getUserIdFromUri(String uri);
    public static String getSessionTokenFromUri(String uri);
}
```

##### <a id="auth-extra-info" />Authentication with extra information
In case it exists, you can retrieve the extra information that the user needs to review while authenticating by calling the following method on the `SessionInfo` object:

```java
public ApproveInfo[] getApproveInfo();
```

Each `ApproveInfo` object is a key-value pair that describes a single piece of information; call the following methods to retrieve the key and value of the object respectively.

```java
public String getKey();
public String getValue();
```

**IMPORTANT**: In case the authentication contains such extra information, it is mandatory that the information is fetched from the server, displayed to the user, and included in the authentication response in order for it to be included in the response signature; otherwise the server will reject the authentication response. Use the following methods to send an authentication response including the authentication information:

```java
class FuturaeClient {
    public void approveAuth(String qrCode, final FuturaeCallback callback, ApproveInfo[] extraInfo);
    public void approveAuth(String userId, String sessionId, final FuturaeCallback callback, ApproveInfo[] extraInfo);
    public void rejectAuth(String userId, String sessionId, boolean reportFraud, final FuturaeCallback callback, ApproveInfo[] extraInfo);
}
```
Jonas Passerini's avatar
Jonas Passerini committed
507
508
509
510
511
512
513
514

[futurae.com]:  http://www.futurae.com

[gradle-app]:        ./Resources/gradle-app.png
[gradle-project]:  ./Resources/gradle-project.png
[config-xml]:  ./Resources/config-xml.png

[android_application]:            http://developer.android.com/reference/android/app/Application.html
Claudio Marforio's avatar
Claudio Marforio committed
515
[build_gradle]:            ./app/build.gradle