# Auth : OTP
- https://en.wikipedia.org/wiki/HMAC-based_one-time_password
- https://en.wikipedia.org/wiki/Time-based_one-time_password
- https://datatracker.ietf.org/doc/html/rfc4226 — HOTP: An HMAC-Based One-Time Password Algorithm
- https://datatracker.ietf.org/doc/html/rfc6238 — TOTP: Time-Based One-Time Password Algorithm
- https://github.com/google/google-authenticator/wiki/Key-Uri-Format
- **OTP** -> *One-Time Password*
- **HOTP** -> *HMAC-based One-Time Password*
- **TOTP** -> *Time-based One-Time Password*
## HOTP
The HOTP algorithm is based on feeding [[HMAC]] a concatenation of a static symmetric key and an increasing counter value.
**Parameters:**
- [[Hashing|hash method]] (default = SHA-1)
- secret key (recommended length = length of hash output = 160 bits (20B) for SHA-1)
- counter
- value length (6-10; default = 6)
Both parties increment the **counter** independently of each other. The algorithm is applied to **secret** + **counter** to generate a **value**. Thus, both parties arrive at same **value**, allowing one party to authenticate the other.
As the output of HMAC-SHA-1 is 160 bits, this **value** is "truncated" to something that can be easily entered by a user (determined by specified **value length**) and composed of digits (0-9) so it can be entered on a telephone.
## TOTP
The TOTP algorithm is built on top of the HOTP algorithm. Instead of a manually incremented **counter**, the current time (epoch seconds) divided by the **step** parameter (default = 30 seconds) is used as the **counter** value.
## otpauth URIs aka "Provisioning URIs"
It's common to generate an "otpauth://" URI containing all the information an authenticator app needs to generate OTP codes for either algorithm. That URI is then turned into a [[QR Codes|QR code]] for easy scanning by apps on mobile devices.
Unfortunately, there is [no official standard](https://shkspr.mobi/blog/2022/05/why-is-there-no-formal-specification-for-otpauth-urls/) for these URIs. The closest thing is this wiki page, which I will refer to as the "Google Draft Spec": https://github.com/google/google-authenticator/wiki/Key-Uri-Format
In general, after surveying a bunch of providers (by attempting to setup 2FA and then decoded the QR code), I can report that the use of these URIs are completely inconsistent in just about every way imaginable.
### Google Draft Spec
```
otpauth://TYPE/LABEL?PARAMETERS
TYPE -> hotp | totp
LABEL -> [ISSUER:]ACCOUNT # ":" can be "%3A" (URL-encoded); spaces allowed after ":"
# ISSUER and ACCOUNT should be URL-encoded, and should not contain ":"
PARAMETERS
secret -> REQUIRED; Base32-encoded (probably 32 chars) ('=' padding should be omitted)
# in the wild, I've seen just as many providers with 16-char secrets, and one using lowercase letters (Google!)
issuer -> optional, but strongly recommended; URL-encoded
# Robinhood.com uses param "issue", which breaks `pyotp.parse_uri()`
algorithm -> optional; SHA1 (default), SHA256, SHA512
digits -> optional; 6 (default) or 8
counter -> REQUIRED if TYPE=hotp; sets intiial counter value
period -> optional; only if TYPE=totp; default = 30 (seconds)
Example: otpauth://totp/Example:
[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=Example
```
> [!NOTE]
> By the Google standard, it is recommend to use both an issuer label prefix and an issuer parameter. Both values must be identical.
> [!WARNING] Apple Deviation
> The Apple standard deviates in two ways:
> - They use the scheme "apple-otpauth".
> - They state the `issuer` label prefix should be “the proper name of your service” while the `issuer` param should be "the domain of the site or app" — which would make them un-equal, which directly violates the Google standard.
>
> Reference: https://developer.apple.com/documentation/authenticationservices/securing-logins-with-icloud-keychain-verification-codes
### Images
The ability to add a logo as part of the registration is not part of any spec.
The FreeOTP app added support for an `image` parameter, which must be an `https` URL pointed at a `png` image. This works in both FreeOTP apps (Android and Apple), but not in any other apps that I tested.
The Microsoft app will show a logo for certain very large corporations — like Coinbase or GitHub — but that's only because those icons were built-in to the Microsoft app on behalf of those corporations.
## Python
### Packages
```
mintotp 36c @ 2024-01-20, 3i, 0pr, 3r (v0.3.0 @ 2021-02-14), 1,319 stars 20 lines; no uris
otpauth 77c @ 2024-04-14, 0i, 0pr, 3r (v2.1.1 @ 2023-09-09), 134 stars uris, no image
pyotp 223c @ 2024-12-02, 4i, 1pr, 18r (v2.9.0 @ 2023-07-27), 3,036 stars uris w/image
totp 78c @ 2024-05-30, 4i, 0pr, 5r (v1.3.0 @ 2020-03-10), 130 stars cli; no uris
```
- [mintotp](https://pypi.org/project/mintotp/) — [src](https://github.com/susam/mintotp/)
- [otpauth](https://pypi.org/project/otpauth/) — [src](https://github.com/authlib/otpauth/), [docs](https://otp.authlib.org/)
- [pyotp](https://pypi.org/project/pyotp/) — [src](https://github.com/pyauth/pyotp/), [docs](https://pyauth.github.io/pyotp/)
- [totp](https://pypi.org/project/totp/) — [src](https://github.com/WhyNotHugo/totp-cli/)
### pyotp
Expects secrets to be strings in Base32 with length = multiple of eight.
```python
import pyotp # importable: OTP, HOTP, TOTP, random_base32, random_hex, parse_uri
## Generating Secret Keys
pyotp.random_base32() -> str # 32-char Base32 (encodes 160b / 20B of data)
pyotp.random_hex() -> str # 40-char hex (")
totp = pyotp.TOTP( secret )
## Generating & Validating TOTP Codes
totp.now() -> str # "123456"
totp.at( int|datetime ) -> str # "123456"
totp.verify( "123456" ) -> bool
## Generating TOTP Provisioning URI ("otpauth://...")
totp.provisioning_uri(
name = "..." # -> LABEL.ACCOUNT
issuer_name = "..." # -> LABEL.ISSUER + param "issuer"
image = "..." # -> param "image"
) -> str
# If you customize the digest, digits, or interval of the TOTP object,
# those params will get added to the provisioning URI.
# .digest().name -> param "algorithm"
# .digits -> param "digits"
# .interval -> param "period"
```
#### Parsing URIs
```python
pyotp.parse_uri( uri ) -> HOTP or TOTP object
totp.digest -> func # totp.digest().name
totp.digits -> int
totp.interval -> int
totp.issuer -> "..."
totp.name -> "..."
totp.secret -> "..."
```
## Apps
https://en.wikipedia.org/wiki/Comparison_of_OTP_applications
Recommendations from providers:
- Coinbase recommends Duo, Google, and Microsoft
- GitHub recommends 1Password, Authy (Twilio), and Microsoft
- Robinhood recommends Authy, Duo, Google, and Microsoft
*Stats below compiled on 2024-Dec-16.*
### Compatability Tests
Using URI:
```
otpauth://totp/Some%20Company:ofer%40somecompany.io?secret=52EJ4XBJLTGXOTIVQBRFN65JTYRCPMSS&issuer=Some%20Company&image=https%3A%2F%2Fgstatic.com%2Frecaptcha%2Fapi2%2Flogo_48.png
LABEL
issuer : "Some Company"
name : "
[email protected]"
PARAMS
issuer : same
image : "https://gstatic.com/recaptcha/api2/logo_48.png"
```
**Android**
| App | Codes | Issuer | Name | Logo |
| ------------ | :---: | :----: | :--: | ------------------------------------ |
| Duo | ✔ | - | ✔ | circle with letter "o" |
| FreeOTP | ✔ | ✔ | ✔ | ✔ |
| Google | ✔ | ✔ | ✔ | no logos |
| Microsoft | ✔ | ✔ | ✔ | circle with letters "PA" |
| Twilio Authy | ✔ | ✔ | ✔ | guessed from crawling somecompany.io |
**Apple**
| App | Codes | Issuer | Name | Logo |
| ------------ | :---: | :----: | :--: | ------------------------------------ |
| Duo | ✔ | - | ✔ | circle with letter "o" |
| FreeOTP | ✔ | ✔ | ✔ | ✔ |
| Google | ✔ | ✔ | ✔ | no logos |
| Microsoft | ✔ | ✔ | ✔ | icon of person |
| Twilio Authy | ✔ | ✔ | ✔ | guessed from crawling somecompany.io |
> [!WARNING] Duo's "User-Friendliness" is Problematic
> To work with Duo, you need to allow validation against either the current or the previous time windows. See: [# Why is the Duo Mobile app third-party passcode timer not in sync with other authenticator app timers?](https://help.duo.com/s/article/6924?language=en_US)
> [!NOTE] What about 1Password?
> 1Password app rejected because it's way too complicated to setup and generally obnoxious to deal with.
### [Android Reference](https://play.google.com/store/apps)
| Rating | Review | Downloads | URL | Name | Logo |
| :----: | -----: | --------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| 4.6 | 1.88M | 100M+ | [play.google.com/store/apps/details?id=com.azure.authenticator](https://play.google.com/store/apps/details?id=com.azure.authenticator) | [Microsoft Authenticator](https://www.microsoft.com/en-us/security/mobile-authenticator-app) |  |
| 3.7 | 545k | 100M+ | [play.google.com/store/apps/details?id=com.google.android.apps.authenticator2](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2) | Google Authenticator |  |
| 3.1 | 83k | 10M+ | [play.google.com/store/apps/details?id=com.authy.authy](https://play.google.com/store/apps/details?id=com.authy.authy) | Twilio Authy Authenticator |  |
| 4.7 | 68k | 10M+ | [play.google.com/store/apps/details?id=com.duosecurity.duomobile](https://play.google.com/store/apps/details?id=com.duosecurity.duomobile) | Duo Mobile |  |
| 4.0 | 58k | 10M+ | [play.google.com/store/apps/details?id=com.authenticator.app.starnest](https://play.google.com/store/apps/details?id=com.authenticator.app.starnest) | Authenticator App by Starnest JSC |  |
| 4.4 | 44k | 10M+ | [play.google.com/store/apps/details?id=authenticator.two.factor.authentication.otp](https://play.google.com/store/apps/details?id=authenticator.two.factor.authentication.otp) | Authenticator App - SafeAuth |  |
| 4.7 | 34k | 10M+ | [play.google.com/store/apps/details?id=com.okta.android.auth](https://play.google.com/store/apps/details?id=com.okta.android.auth) | Okta Verify |  |
| 3.4 | 17k | 5M+ | [play.google.com/store/apps/details?id=com.rsa.securidapp](https://play.google.com/store/apps/details?id=com.rsa.securidapp) | RSA Authenticator (SecurID) |  |
| 4.3 | 31k | 1M+ | [play.google.com/store/apps/details?id=com.twofasapp](https://play.google.com/store/apps/details?id=com.twofasapp) | 2FA Authenticator (2FAS) |  |
| 4.4 | 19k | 1M+ | [play.google.com/store/apps/details?id=com.salesforce.authenticator](https://play.google.com/store/apps/details?id=com.salesforce.authenticator) | Salesforce Authenticator |  |
| 4.2 | 19k | 1M+ | [play.google.com/store/apps/details?id=io.enpass.app](https://play.google.com/store/apps/details?id=io.enpass.app) | Enpass Password Manager |  |
| 4.5 | 15k | 1M+ | [play.google.com/store/apps/details?id=com.lastpass.authenticator](https://play.google.com/store/apps/details?id=com.lastpass.authenticator) | LastPass Authenticator |  |
| 4.7 | 9k | 1M+ | [play.google.com/store/apps/details?id=com.onepassword.android](https://play.google.com/store/apps/details?id=com.onepassword.android) | 1Password: Password Manager |  |
| 3.2 | 5k | 1M+ | [play.google.com/store/apps/details?id=org.fedorahosted.freeotp](https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp) | FreeOTP Authenticator |  |
| 4.6 | 4k | 500K+ | [play.google.com/store/apps/details?id=com.beemdevelopment.aegis](https://play.google.com/store/apps/details?id=com.beemdevelopment.aegis) | Aegis Authenticator - 2FA App |  |
| 3.7 | <1k | 50K+ | [play.google.com/store/apps/details?id=com.bitwarden.authenticator](https://play.google.com/store/apps/details?id=com.bitwarden.authenticator) | [Bitwarden Authenticator](https://bitwarden.com/products/authenticator/) |  |
### [Apple Reference](https://www.fnd.io/)
*Built-in:* [Apple Keychain](https://developer.apple.com/documentation/authenticationservices/securing-logins-with-icloud-keychain-verification-codes)
| Rating | Review | URL | Name |
| :----: | -----: | :--------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------- |
| 4.9 | 1.4M | [apps.apple.com/us/app/duo-mobile/id422663827](https://apps.apple.com/us/app/duo-mobile/id422663827) | Duo Mobile |
| 4.8 | 763k | [apps.apple.com/us/app/google-authenticator/id388497605](https://apps.apple.com/us/app/google-authenticator/id388497605) | Google Authenticator |
| 4.8 | 455k | [apps.apple.com/us/app/microsoft-authenticator/id983156458](https://apps.apple.com/us/app/microsoft-authenticator/id983156458) | [Microsoft Authenticator](https://www.microsoft.com/en-us/security/mobile-authenticator-app) |
| 4.3 | 99k | [apps.apple.com/us/app/id-me-authenticator/id1446335066](https://apps.apple.com/us/app/id-me-authenticator/id1446335066) | ID.me Authenticator |
| 4.7 | 45k | [apps.apple.com/us/app/twilio-authy/id494168017](https://apps.apple.com/us/app/twilio-authy/id494168017) | Twilio Authy |
| 4.7 | 39k | [apps.apple.com/us/app/lastpass-authenticator/id1079110004](https://apps.apple.com/us/app/lastpass-authenticator/id1079110004) | LastPass Authenticator |
| 4.3 | 30k | [apps.apple.com/us/app/1password-7-password-manager/id568903335](https://apps.apple.com/us/app/1password-7-password-manager/id568903335) | 1Password 7 by AgileBits Inc |
| 4.7 | 27k | [apps.apple.com/us/app/2fa-authenticator-2fas/id1217793794](https://apps.apple.com/us/app/2fa-authenticator-2fas/id1217793794) | 2FA Authenticator (2FAS) |
| 4.4 | 17k | [apps.apple.com/us/app/authenticator-app/id6443508147](https://apps.apple.com/us/app/authenticator-app/id6443508147) | Authenticator App by Codenhagen.IO ApS |
| 4.8 | 11k | [apps.apple.com/us/app/authenticator-app/id1610508128](https://apps.apple.com/us/app/authenticator-app/id1610508128) | Authenticator App+ by Rocker Apps GmbH |
| 4.6 | 3k | [apps.apple.com/us/app/salesforce-authenticator/id782057975](https://apps.apple.com/us/app/salesforce-authenticator/id782057975) | Salesforce Authenticator |
| 4.3 | 2k | [apps.apple.com/us/app/authenticator-app/id1538761576](https://apps.apple.com/us/app/authenticator-app/id1538761576) | Authenticator App by 2Stable |
| 4.3 | 1k | [apps.apple.com/us/app/enpass-password-manager/id455566716](https://apps.apple.com/us/app/enpass-password-manager/id455566716) | Enpass Password Manager |
| 3.6 | <1k | [apps.apple.com/us/app/bitwarden-authenticator/id6497335175](https://apps.apple.com/us/app/bitwarden-authenticator/id6497335175) | Bitwarden Authenticator |
| 3.2 | 160 | [apps.apple.com/us/app/freeotp-authenticator/id872559395](https://apps.apple.com/us/app/freeotp-authenticator/id872559395) | FreeOTP |