ChangelogEdit pageSTAFFOpen dashboard

Starting with a device credential

With the SDK API key, Bubbl gets every install its own device credential by itself. Starting with a credential is for phones that were paired with a code instead, such as Bubbl's Showcase app.

How an install gets its credential#

Every request Bubbl sends from a phone is signed with that install's own device credential: a key ID (starting bdk_) and a secret. When you start Bubbl with your SDK API key, you never handle one:

  1. On first launch, Bubbl makes an install ID for the app install and keeps it.
  2. It registers the install with your API key. The key only says which workspace the install belongs to.
  3. Bubbl's server issues the install its own credential. The secret is sent this once, and Bubbl keeps it in the Android Keystore or the iOS Keychain.
  4. Bubbl signs every later request with it. If the server refuses the credential (it was revoked, for example), Bubbl registers the install again by itself, once, and carries on with the new one.

Registering again replaces the install's credential, and the old one stops working. You don't issue, store or rotate credentials yourself, so start Bubbl with your API key.

Where else a credential comes from#

The only other way to get a credential is to pair a phone with a code. That's how Bubbl's Showcase app connects to a workspace: with the setup QR (or its short code) from the dashboard's See it on your phone drawer, which lasts 30 minutes, or with a demo PIN from a Bubbl admin. Phones paired this way are Showcase phones: they aren't billed, they can preview the workspace's notifications, and the See it on your phone drawer can disconnect them all at once.

There's no dashboard page or server API that issues credentials for your own app's installs. Starting with a credential is for apps that get theirs by pairing, which today means the Showcase app. If you do have a credential from a pairing flow, start Bubbl with it like this.

  1. 1
    Keep the credential safe
    Pairing gives you the key ID and secret; the install ID is the one you paired with. Keep your copy of the secret in secure storage, the Android Keystore or the iOS Keychain, and never log it. Bubbl keeps its own copy there too.
  2. 2
    Start Bubbl with it at every launch
    Call the credential start where you'd call start with a key, the same way at every launch, with your workspace's API address (pairing returns it as base_url). installId must be the install the credential was issued for. Flutter and React Native name it startWithCredential, beside start.
    APP.KT
    class App : Application() {
        override fun onCreate() {
            super.onCreate()
            val credential = BubblCredential(keyId, secret, installId)   // from your provisioning
            Bubbl.start(this, credential, BubblOptions(baseUrl = "https://api.bubbl.tech"))
        }
    }
    SWIFT
    let credential = BubblCredential(keyId: keyId, secret: secret, installId: installId)
    Bubbl.start(credential: credential, options: BubblOptions(baseUrl: "https://api.bubbl.tech"))
    DART
    await Bubbl.startWithCredential(
      BubblCredential(keyId: keyId, secret: secret, installId: installId),
      options: const BubblOptions(baseUrl: 'https://api.bubbl.tech'),
    );
    TS
    Bubbl.startWithCredential({ keyId, secret, installId }, { baseUrl: 'https://api.bubbl.tech' });
  3. 3
    Check diagnostics
    registered is true as soon as Bubbl has the credential: there's no registration to wait for. installId is the one you passed, and credentialRejected should be false.
    KOTLIN
    Bubbl.diagnostics { d -> Log.i("App", "registered=${d.registered} installId=${d.installId} rejected=${d.credentialRejected}") }
    SWIFT
    let d = await Bubbl.diagnostics()
    print(d.registered, d.installId ?? "none", d.credentialRejected)
    DART
    final d = await Bubbl.diagnostics();
    debugPrint('registered=${d.registered} installId=${d.installId} rejected=${d.credentialRejected}');
    TS
    const d = await Bubbl.diagnostics();
    console.log(d.registered, d.installId, d.credentialRejected);

Changing credentials#

  • Starting again with the same credential changes nothing.
  • A different credential, or switching between an API key and a credential, starts afresh as a new device: what Bubbl kept on the phone is cleared first, and nothing from before is sent under the new identity. The user's consent is kept.

When the server refuses it#

If the server refuses the credential (it was revoked, for example), Bubbl stops and tells you:

  • a credential-rejected event: BubblEvent.CredentialRejected on Android, .credentialRejected on iOS, BubblCredentialRejected in Flutter, { type: 'credential.rejected' } in React Native;
  • in diagnostics, credentialRejected true.

Bubbl doesn't retry on its own. The next start tries again, so start it with a new credential.

Mistakes#

An empty key ID, secret or install ID is a mistake like an empty API key, reported as Bubbl.start: the credential is incomplete. On Android the native Bubbl.start throws it as an IllegalArgumentException; on iOS, and in Flutter and React Native, it's logged and Bubbl doesn't start. The secret is never in the message: BubblCredential leaves it out of toString and descriptions.