The provisioning URI¶
An authenticator application is configured by a single string: an otpauth:// URI holding the secret and
every parameter needed to reproduce the codes. It is what a QR code carries.
use OTPHP\TOTP;
$totp = TOTP::createFromSecret('JBSWY3DPEHPK3PXP', $clock)
->withLabel('alice@example.com')
->withIssuer('My Service');
echo $totp->getProvisioningUri();
Its shape is the key URI format Google Authenticator defined:
The type is totp or hotp. The path is the label, with the issuer joined in front of it by a colon when
there is one. The parameters carry the rest, sorted by name.
A label is required¶
getProvisioningUri() throws InvalidLabelException when neither a label nor an issuer is set: there
would be nothing to name the account with. Set the label before you call it. See
The label and the issuer.
Defaults are left out¶
A parameter at its default value is omitted, because an application that does not read it will assume the same default anyway:
$totp->withPeriod(30)->getProvisioningUri(); // no "period="
$totp->withPeriod(60)->getProvisioningUri(); // "period=60"
$totp->withEpoch(0)->getProvisioningUri(); // no "epoch="
A fully specified TOTP looks like this:
otpauth://totp/My%20Service%3Aalice%40example.com?algorithm=sha512&digits=8&issuer=My%20Service&period=10&secret=JBSWY3DPEHPK3PXP
And a HOTP carries its counter, which is never omitted:
It is the secret, written out¶
Treat the URI exactly as you treat the secret. It goes to the user's browser once, over TLS, in a page that is not cached; it does not go into a log, an exception message, an analytics event or a third-party service. QR codes is about the last of those.
It round-trips¶
Everything the URI holds — the custom parameters included — can be read back into an equivalent object:
Which makes the URI a reasonable thing to store, instead of the secret and a scattering of columns. See The factory and What to store.