# 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) | ![logo\|48](https://play-lh.googleusercontent.com/_1CV99jklLbXuun-6E7eCPR-sKKeZc602rhw_QHZz-qm7xrPdgWsJVc7NtFkkliI8No=w240-h480) | | 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 | ![logo\|48](https://play-lh.googleusercontent.com/NntMALIH4odanPPYSqUOXsX8zy_giiK2olJiqkcxwFIOOspVrhMi9Miv6LYdRnKIg-3R=w240-h480) | | 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 | ![logo](https://play-lh.googleusercontent.com/NxyEuJRx4jjR1Q9PXOPGExFQXDKr_pZJ61Cb15eR0aX3UTZKAxWsXvK9Gh4K-NUd5A=s48) | | 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 | ![logo\|48](https://play-lh.googleusercontent.com/dpE6aQQqc2Obn9ddW741YegLaoTNNPfzmLhC2qnMPoZPM50DOkJyRhiQ2gw8dSLoNQ=w240-h480) | | 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 | ![logo](https://play-lh.googleusercontent.com/3O3LaxrwVazfmU7jlyrY7dxja-FodFwYlkQW_JI-52-X49gS7Sv8J78iWzqDokBHghuS=s48) | | 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 | ![logo\|48](https://play-lh.googleusercontent.com/xJQeWZM2E-pMgNSCum_GF-kAhI46cAC-ac3Owt3RFu8S0sjrFuUf2Z_3ZjCI797sUA=w240-h480) | | 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 | ![logo\|48](https://play-lh.googleusercontent.com/IOMxgXpJHi-Yk3ukLH0HFKPqoP7rJWeQusgGJ4ZnijcYffbvIzw8ldWUla0frMV_g1Q=w240-h480) | | 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) | ![logo\|48](https://play-lh.googleusercontent.com/TcPpYxQU3aR3jV6ik_OYdV2_40f7JSb1Fvo0aTMcMRlk3oTKcMl3YeZlILDpNmeLdJMN=w240-h480) | | 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) | ![logo\|48](https://play-lh.googleusercontent.com/F2wwwaQwutP2MvUJbjRm9knqRlUxSVghbPncqLr2IHvkyMvPlxjphiwC3Fhr9tOL60lP=w240-h480) | | 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 | ![logo\|48](https://play-lh.googleusercontent.com/GmrRixZ7OVZwOGOOII2b2mLVO3Odb4a5pgu7l461rxvw40gl9ezvldRMp-FQiGlWhQ=w240-h480) | | 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 | ![logo](https://play-lh.googleusercontent.com/1qKnx7fZcyjQjoZpKaUHQ8lhNvzaKO_ECubBYI0K0zKG3qYqWyDJFOogqB4CJRkcPeZ_=s48) | | 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 | ![logo\|48](https://play-lh.googleusercontent.com/O40QiaHe7o8gXlnjhM3bNFJeyQeDMH4ftV0zridji7KnHLv7kymJcWS5BtNmiAY1YghS=w240-h480) | | 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 | ![logo\|48](https://play-lh.googleusercontent.com/RyPWI5dSfKqMUnuEYqMqQPMLv8AvKehIhut1yIKJU91HWpvtUHPj1rzn_UHwpEqH2a0=w240-h480) | | 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 | ![logo\|48](https://play-lh.googleusercontent.com/sqAeB4c4akVOOxfmfR6BJcNEFc_bNjS3VVRys3FVvvwhcnT5aH3LRZMIoAXBBTt8cvY=w240-h480) | | 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 | ![logo\|48](https://play-lh.googleusercontent.com/qDzsOmoRT9o6QTElCaRJElAtfYW-nnOadwIInb6bXSEKexB211SsEtSeZrF5xm_lKUY=w240-h480) | | 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/) | ![logo\|48](https://play-lh.googleusercontent.com/pwZhD8cLGl01nj1uNZJ6VM7PD89xPmsc8N3-LHt9Ynuh746S8sTL6-XSn2IhKgQNXA=w240-h480) | ### [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 |