Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Using blisache-flutter with Flutter applications

blisache-flutter is a Flutter plugin exposing the API as simple dart functions to be called. An example flutter app is available on the github repo.

Requirements

This plugin requires :

  • An account on Blisache with a registered domain
  • App association files (assetlinks.json on android, apple-app-site-association on ios/macos) hosted at your domain’s website

Integration

Declare a new dependency in your pubspec.yaml

# pubspec.yaml

dependencies:
  blisache: ^1.0.0

Creating an account

import 'dart:convert';
import 'package:blisache/blisache.dart';
import 'package:http/http.dart' as http;

// Create an instance of the plugin
final yourDomain = 'example.com';
final blisachePlugin = Blisache(domainForAll: yourDomain);

// Call `register()` with user login and name
final registerSignedResponse = await blisachePlugin.register(login: "mylogin", name: "my user name");

// Forward `registerSignedResponse` to your backend's register endpoint for further validations
// See https://github.com/Blisache/blisache/blob/main/flutter%2Bnodejs/server.js
// See https://blisache.com/documentation/guide/integration/server_side_validation.html
final registerResponse = await http.post(
    Uri.https(yourDomain, '/server/register'),
    headers: { "Content-Type": "application/json" },
    body: jsonEncode(registerSignedResponse.toJson())
);

// Assert registration success
assert(registerResponse.statusCode == 200);
print("registered");

Authenticating a user

import 'dart:convert';
import 'package:blisache/blisache.dart';
import 'package:http/http.dart' as http;

// Create an instance of the plugin
final yourDomain = 'example.com';
final blisachePlugin = Blisache(domainForAll: yourDomain);

// Call `authenticate()` with optional login (null for resident keys)
final authenticateSignedResponse = await blisachePlugin.authenticate(login: "mylogin");

// Forward `authenticateSignedResponse` to your backend's authenticate endpoint for further validations
// See https://github.com/Blisache/blisache/blob/main/flutter%2Bnodejs/server.js
// See https://blisache.com/documentation/guide/integration/server_side_validation.html
final authenticateResponse = await http.post(
    Uri.https(yourDomain, '/server/authenticate'),
    headers: { "Content-Type": "application/json" },
    body: jsonEncode(authenticateSignedResponse.toJson())
);

// Assert authentication success
assert(authenticateResponse.statusCode == 200);
print("authenticated");

App-site association files

When building for android, ios or macos platforms you will need to host an app-site association file under your domain’s website.

Android assetlinks.json

Android fetch your assetlinks.json file at https://<your_domain_here>/.well-known/assetlinks.json and check if app package_name and sha256_cert_fingerprints match.

Example of assetlinks.json file :

[
    {
        "relation": [
            "delegate_permission/common.handle_all_urls",
            "delegate_permission/common.get_login_creds"
        ],
        "target": {
            "namespace": "android_app",
            "package_name": "<your_app_package_name>",
            "sha256_cert_fingerprints": [
                "<you_app_sha256_cert_fingerprints>"
            ]
        }
    }
]

Ios/Macos apple-app-site-association

Ios and macos products fetch your apple-app-site-association file at https://<your_domain_here>/.well-known/apple-app-site-association and check if your app-id match.

Example of apple-app-site-association file :

{
   "webcredentials": {
      "apps": ["<team_id>.<bundle_id>"]
   }
}

Exposed functions

Here are the prototypes of the exposed functions :

Future<SignedResponse> register({ required String login, required String name });

register() initiates a new registration to the API, prompts the authenticator for a new key, and registers the created key to the API. Thats mean we create a new account or new user.

Future<SignedResponse> authenticate({ String? login });

authenticate() initiates a new authentication to the API, prompts the authenticator for an already registered key and authenticates the user to the API.

Future<SignedResponse> credentialList({ String? login });

credentialList() authenticates the user with authenticate() and retreives the credentials registered to the API for that user.

Future<SignedResponse> credentialAdd({ required String login, required String name });

credentialAdd() authenticates the user with authenticate() and registers a new key for that user using register().

Future<SignedResponse> credentialRevoke({ String? login, required int credentialId });

credentialRevoke() authenticates the user with authenticate() and unregisters the user’s target credential.

The login is the account name. It is often set as the email address of the user. It is sent to the API and anonymised for storage.

The name is the name of the user. It is stored in the authenticator and used as display name. It is not sent to the API.

login and name are mandatory in registration-related endpoints.

In authentication-related endpoints login is optional. If login present, a server-side credential search is performed. When login is absent, a discoverable resident key (passkey) is selected for the ceremony with possible user prompt.

Each of these functions returns a SignedResponse. This is a data object containing a message and its associated signature. The message is the json response from the API serialized as a bytes array. The signature is the signature of the message signed from Blisache servers also serialized as a bytes array. A SignedResponse wraps success and error responses from the API and should be sent to your backend for further processing.