PHPackages                             infocyph/otp - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. infocyph/otp

ActiveLibrary

infocyph/otp
============

Simple &amp; Secure Generic OTP, OCRA (RFC6287), TOTP (RFC6238) &amp; HOTP (RFC4226) solution!

4.01.4(3mo ago)136.4k↓50%MITPHPPHP &gt;=8.2CI passing

Since Nov 8Pushed 3mo ago1 watchersCompare

[ Source](https://github.com/infocyph/OTP)[ Packagist](https://packagist.org/packages/infocyph/otp)[ RSS](/packages/infocyph-otp/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (8)Versions (17)Used By (0)

OTP
===

[](#otp)

[![Security & Standards](https://github.com/infocyph/OTP/actions/workflows/build.yml/badge.svg)](https://github.com/infocyph/OTP/actions/workflows/build.yml)[![Codacy Badge](https://camo.githubusercontent.com/ade0efe19c86cf73cdadaabde3be496cdbc7492080b03e2bb29fbc15806ead86/68747470733a2f2f6170702e636f646163792e636f6d2f70726f6a6563742f62616467652f47726164652f3162373837336464326264663438373438633836323635663234646230623334)](https://app.codacy.com/gh/infocyph/OTP/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)[![Packagist Downloads (custom server)](https://camo.githubusercontent.com/1c0c815f0b97901ddf94f7a99aa2351aad86310c3aced2a1e7da69c0b4b0fa6c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f696e666f637970682f6f74703f636f6c6f723d677265656e266c696e6b3d68747470732533412532462532467061636b61676973742e6f72672532467061636b61676573253246696e666f637970682532466f7470)](https://camo.githubusercontent.com/1c0c815f0b97901ddf94f7a99aa2351aad86310c3aced2a1e7da69c0b4b0fa6c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f696e666f637970682f6f74703f636f6c6f723d677265656e266c696e6b3d68747470732533412532462532467061636b61676973742e6f72672532467061636b61676573253246696e666f637970682532466f7470)[![License: MIT](https://camo.githubusercontent.com/784362b26e4b3546254f1893e778ba64616e362bd6ac791991d2c9e880a3a64e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d677265656e2e737667)](https://opensource.org/licenses/MIT)[![Packagist Version](https://camo.githubusercontent.com/c79fb7752a0ade5e79642a1e68c8f16ae9986706e5234a55a126d9aaf574336e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f696e666f637970682f6f7470)](https://camo.githubusercontent.com/c79fb7752a0ade5e79642a1e68c8f16ae9986706e5234a55a126d9aaf574336e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f696e666f637970682f6f7470)[![Packagist PHP Version](https://camo.githubusercontent.com/ee8bfbf037061e85694cc00477e169da19800c28570a2ab89eccfe8945805bb4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646570656e64656e63792d762f696e666f637970682f6f74702f706870)](https://camo.githubusercontent.com/ee8bfbf037061e85694cc00477e169da19800c28570a2ab89eccfe8945805bb4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646570656e64656e63792d762f696e666f637970682f6f74702f706870)[![GitHub code size in bytes](https://camo.githubusercontent.com/3cbb8bf6715d7f3b27512aac80878ea7f1a49e1160a4995bfa90ea31af6210d4/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c616e6775616765732f636f64652d73697a652f696e666f637970682f6f7470)](https://camo.githubusercontent.com/3cbb8bf6715d7f3b27512aac80878ea7f1a49e1160a4995bfa90ea31af6210d4/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c616e6775616765732f636f64652d73697a652f696e666f637970682f6f7470)[![]()](https://visitor-badge.laobi.icu/badge?page_id=infocyph.com)

Simple but Secure AIO OTP solution. Supports,

- Generic OTP (storage-less otp solution)
- TOTP (RFC6238)
- HOTP (RFC4226)
- OCRA (RFC6287)

Table of Contents
-----------------

[](#table-of-contents)

- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Why this library?](#why-this-library)
- [Usage](#usage)
    - [HOTP (RFC4226)](#hotp-rfc4226)
    - [TOTP (RFC6238)](#totp-rfc6238)
    - [Generic OTP](#generic-otp)
    - [OCRA (RFC6287)](#ocra-rfc6287)
- [Support](#support)
- [References](#references)

Prerequisites
-------------

[](#prerequisites)

Language: PHP 8.2/+

Library VersionPHP Version3.x.x/+8.2.x or Higher2.x.x8.x.x1.x.x7.x.xInstallation
------------

[](#installation)

```
composer require infocyph/otp

```

Why this library?
-----------------

[](#why-this-library)

#### TOTP &amp; HOTP

[](#totp--hotp)

- Uses offline QR code generator (no more exposing your secret online)
- Time-safe Base32 encoding (30 seconds validity means 30 seconds)

#### Generic OTP

[](#generic-otp)

- No need to dedicate extra storage/db for User information (just build a unique signature)

#### OCRA

[](#ocra)

- One of a few implementation in PHP, easy to use

Usage
-----

[](#usage)

### HOTP (RFC4226)

[](#hotp-rfc4226)

- Generate secret

```
$secret = \Infocyph\OTP\HOTP::generateSecret();
```

- Get QR Code Image for secret $secret (in SVG format)

```
// supports digit count in 2nd parameter, recommended to be either 6 or 8 (default 6)
(new \Infocyph\OTP\HOTP($secret))
// only required if the counter is being imported from another system or if it is old, & for QR only
->setCounter(3)
// default is sha1; Caution: many app (in fact, most of them) have algorithm limitation
->setAlgorithm('sha256')
// or `getProvisioningUri` just to get the URI
->getProvisioningUriQR('TestName', 'abc@def.ghi');
```

> The `getProvisioningUriQR` &amp; `getProvisioningUri` accepts 3rd parameter, where it takes array of parameters `['algorithm', 'digits', 'period', 'counter']`. Problem you might encounter, with the URI/Image is that most of the OTP generator might not support all of those options. In that case, passing in a blank array will remove all the optional keys, or you can pass in selective parameters as you need. Additionally, you can also pass in additional parameter to reflect in URI string or QR image in 4th parameter. But be cautious that, it might not be supported by the Client Apps.

- Get current OTP for a given counter

```
$counter = 346;
$otp = (new \Infocyph\OTP\HOTP($secret))->getOTP($counter);
```

- Verify

```
(new \Infocyph\OTP\HOTP($secret))->verify($otp,$counter);
```

### TOTP (RFC6238)

[](#totp-rfc6238)

- Generate secret

```
$secret = \Infocyph\OTP\TOTP::generateSecret();
```

- Get QR Code Image for secret $secret (in SVG format)

```
// supports digit count in 2nd parameter, recommended to be either 6 or 8 (default 6)
(new \Infocyph\OTP\TOTP($secret))
// default is sha1; Caution: many app (in fact, most of them) have algorithm limitation
->setAlgorithm('sha256')
// or `getProvisioningUri` just to get the URI
->getProvisioningUriQR('TestName', 'abc@def.ghi');
```

> The `getProvisioningUriQR` &amp; `getProvisioningUri` accepts 3rd parameter, where it takes array of parameters `['algorithm', 'digits', 'period', 'counter']`. Problem you might encounter, with the URI/Image is that most of the OTP generator might not support all of those options. In that case, passing in a blank array will remove all the optional keys, or you can pass in selective parameters as you need. Additionally, you can also pass in additional parameter to reflect in URI string or QR image in 4th parameter. But be cautious that, it might not be supported by the Client Apps.

- Get current OTP for a given counter

```
$counter = 346;
$otp = (new \Infocyph\OTP\TOTP($secret))->getOTP($counter);
// or get OTP for another specified epoch time
$otp = (new \Infocyph\OTP\TOTP($secret))->getOTP(1604820275);
```

- Verify

```
(new \Infocyph\OTP\TOTP($secret))->verify($otp);
// or verify for a specified time
(new \Infocyph\OTP\TOTP($secret))->verify($otp, 1604820275);
```

> On 3rd parameter `(bool)` it supports, enabling leeway. If enabled, it will also check with last segment's generated otp.

### Generic OTP

[](#generic-otp-1)

- Initiate

```
/**
* Param 1 is OTP length (default 6)
* Param 2 is validity in seconds (default 30)
* Param 3 is retry count on failure (default 3)
*/
$otpInstance = new \Infocyph\OTP\OTP(4, 60, 2);
```

- Generate &amp; get the OTP

```
$otp = $otpInstance->generate('an unique signature for a cause');
```

- Verify the OTP

```
$otpInstance->verify('an unique signature for a cause', $otp);
```

> On 3rd parameter setting false `will keep the record till the otp is verified or expired`. By default, `will keep the record till the key name match or the otp is verified or expired`

- Delete a record

```
$otpInstance->delete('an unique signature for a cause');
```

- Flush all the existing OTPs (if any)

```
$otpInstance->flush()
```

> Generic OTP uses **temporary location** for storage, make sure you have proper access permission

### OCRA (RFC6287)

[](#ocra-rfc6287)

```
// Example usage:
$sharedKey = 'mySecretKey'; // Replace with your actual shared key (binary format)
$challenge = '123456'; // Replace with your challenge value
$counter = 0; // Replace with the appropriate counter value

// Create an OCRA instance
$suite = new \Infocyph\OTP\OCRA('OCRA-1:HOTP-SHA1-6:C-QN08', $sharedKey);

// If the OCRA suite supports session, set the session
$suite->setSession('...');

// If the OCRA suite supports time format, set the time
$suite->setTime(new \DateTime());

// If the OCRA suite supports pin, set the pin
$suite->setPin('...');

// Generate the OCRA value
$suite->generate($challenge, $counter);
```

#### Forming an OCRA Suite

[](#forming-an-ocra-suite)

According to current RFC6287, an example string should be in the following format:

```
OCRA-1:HOTP-SHA1-6:C-QN08-PSHA1
```

Here `OCRA-1:HOTP-` is fixed as of current documentation.

- SHA1 is cryptographic hash function. (supported: SHA1, SHA256, SHA512)
- 6 is the number of digits in the generated OTP. (supported: 0, 4-10)
- C denotes counter support (optional)
- QN08 denotes the mode (it can be either of QNxx, QAxx, QHxx)

Format (F)Up to Length (xx)A (alphanumeric)04-64N (numeric)04-64H (hexadecimal)04-64- Next part is optional &amp; little tricky
    - PSHA1 denotes the hash function used for pin support (it can be either of PSHA1, PSHA256, PSHA512)
    - S (not in example) denotes session length (3 digits)
    - T (not in example) denotes time format as of below table,

Time-Step Size (G)Examples\[1-59\]Snumber of seconds, e.g., 20S\[1-59\]Mnumber of minutes, e.g., 5M\[0-48\]Hnumber of hours, e.g., 24HSupport
-------

[](#support)

Having trouble? Create an issue!

References
----------

[](#references)

- HOTP (RFC4226):
- TOTP (RFC6238):
- OCRA (RFC6287):

###  Health Score

52

—

FairBetter than 96% of packages

Maintenance78

Regular maintenance activity

Popularity29

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity74

Established project with proven stability

 Bus Factor1

Top contributor holds 98.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~135 days

Recently: every ~154 days

Total

15

Last Release

118d ago

Major Versions

1.0.2 → 2.02023-11-14

2.02 → 3.02024-01-10

3.0 → 4.02024-04-26

PHP version history (3 changes)1.0.0PHP &gt;=7.1

2.0PHP &gt;=8.0

3.0PHP &gt;=8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/33b750b84ab22f2038ef9b90ee48f2fcdaab6b5698e9f956a89a152466200b63?d=identicon)[abmmhasan](/maintainers/abmmhasan)

---

Top Contributors

[![abmmhasan](https://avatars.githubusercontent.com/u/7711128?v=4)](https://github.com/abmmhasan "abmmhasan (63 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")

---

Tags

hotpocraotpotphpphprfc4226rfc6238rfc6287totpotphotptotphmacrfc4226rfc6238shaocrarfc6287sms-otpemail-otp

###  Code Quality

TestsPest

Static AnalysisRector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/infocyph-otp/health.svg)

```
[![Health](https://phpackages.com/badges/infocyph-otp/health.svg)](https://phpackages.com/packages/infocyph-otp)
```

###  Alternatives

[christian-riesen/otp

One Time Passwords, hotp and totp according to RFC4226 and RFC6238

885.1M6](/packages/christian-riesen-otp)[spomky-labs/otphp

A PHP library for generating one time passwords according to RFC 4226 (HOTP Algorithm) and the RFC 6238 (TOTP Algorithm) and compatible with Google Authenticator

1.5k46.1M119](/packages/spomky-labs-otphp)[chillerlan/php-authenticator

A generator for counter- and time based 2-factor authentication codes (Google Authenticator). PHP 8.2+

58119.1k2](/packages/chillerlan-php-authenticator)[rych/otp

PHP implementation of the OATH one-time password standards

36265.8k4](/packages/rych-otp)[paragonie/multi-factor

Vendor-agnostic two-factor authentication library

142195.5k2](/packages/paragonie-multi-factor)[firehed/security

Security tools for PHP

2374.9k2](/packages/firehed-security)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
