Explanation

The signer's journey

Three surfaces take turns during one signature: your pages, Cleverbase's pages in the same browser, and the Cleverbase app on the signer's phone. Only the first is yours. The Cleverbase pages and the app screens are part of the qualified service and cannot be styled, skinned, embedded or replaced: they are where the signer is told what they are about to sign and where sole control over the key is exercised. Plan your flow around them instead of around a design.

Step through it below; the browser column and the phone column show who owns the screen at each moment, and what your backend is doing meanwhile.

Who owns which screen

SurfaceOwnerYou control
The page with the document and the "Sign" buttonYouEverything
The authorization pages (login, QR, consent, waiting, result)CleverbaseNothing but the redirect_uri you send the signer back to, and the moment you start it
The app screens (request, PIN, result)CleverbaseNothing
The page the signer lands on afterwardsYouEverything

The Cleverbase pages are served from the host in your authorize URL: connect.cleverbase.com, or connect.acc.cleverbase.com on acceptance. Do not open them in an iframe or a webview you control; treat them as a full-page redirect, the way you would a payment provider.

Desktop and mobile are not the same flow

  • Desktop. The first Cleverbase page shows a QR code. The signer scans it with the Cleverbase app, and the browser page moves on by itself once the app has confirmed. Two devices, one session, bound to each other by that scan. The second authorization does not ask for another scan: it reuses that binding, so the browser shows a waiting screen with the signer's progress while the app asks for the confirmation and the PIN.
  • Mobile. The same URL opens the app directly through an app link, so the QR step does not appear. The signer comes back to the browser through the redirect.

That difference is invisible in your code, both are the same /oauth2/authorize call, but very visible in testing: on a phone you never see a QR code, and on a desktop you always need a second device.

Two redirects, and what comes back

Both authorization legs end in a redirect to your redirect_uri. That is your callback, and there is no other one: Cleverbase does not call your backend, there is no webhook and no server-to-server notification. If the signer never comes back, nothing tells you.

SuccessRefusal, timeout or abort
First leg (scope=service)?code=...&state=...?error=...&state=...
Second leg (scope=credential)?code=...&state=..., exchange for the SAD?error=...&state=..., nothing was signed

So build for three outcomes per leg, not two: success, an error redirect, and silence. Silence is the common one in practice, because the signer closes the tab, loses the app session or walks away. Keep the intermediate state under your state value with a timeout of your own and clean it up; our own implementation expires it after ten minutes.

Two more things about the redirect:

  • state is yours and single use. It is how you find the prepared document, the digest and the signing time again when the browser comes back. Pop it when you use it, so a replayed redirect cannot start a second signature.
  • The signer may come back on a different device or browser tab than the one that left, especially on mobile. If your session cookie is the only thing tying the redirect to the flow, that breaks; the state parameter is the reliable link.

What the signer is shown about the document

The app shows who is asking for a signature, not what is in the document. Cleverbase never receives the document, so it cannot display it. The signer reads the document on your page, before the flow starts, and confirms in the app afterwards.

That has a consequence for your UI: the document the signer read and the hash you authorize must be the same thing. Show the document, then start the flow; do not let anything regenerate the PDF in between.

Timing you have to design for

  • The SAD from the second leg is valid for 300 seconds and only for the hash or hashes you authorized. Call signHash right away, in the redirect handler, not from a queue that might run later.
  • The first leg's access token lives long enough for credentials/list, credentials/info and, later, signHash. Keep it for the whole flow.
  • Between the two legs sits your own work (prepare and digest). Do it in the first redirect handler and have the second authorize URL ready before you send the signer on, so they do not wait on a spinner.

Testing this

  • You need a real phone with the Cleverbase app, registered on the same environment (acceptance app for connect.acc). There is no emulator and no test mode that skips the app.
  • Test the refusal path. Tap "Refuse" in the app and confirm your code handles the error redirect and cleans up the prepared state.
  • Test the silence path. Close the tab on the Cleverbase page and confirm nothing hangs and no half-prepared document is left behind.
  • Test the expiry path. Authorize, then wait more than five minutes before calling signHash; you should get a failure and need a new authorization. Better to see it once in testing than at a customer.
  • Test on a phone and on a desktop. They are different journeys for the signer, and the mobile one skips a screen you may have built copy around.
  • Signatures made on acceptance use test certificates and are not qualified, but the screens and the timings are the real ones.

What Cleverbase does not do

  • No document storage. The PDF stays with you for the whole flow and afterwards. There is nothing to fetch later.
  • No timestamp inside the signature. A qualified timestamp is a separate call to a TSA, made by you. See "The PAdES levels".
  • No webhook. Only the redirects above.
  • No customization of the pages or the app. Not the logo, not the copy, not the order of the screens.