a4sex / self-signed-token
A simple self-signed token based on a secret string and creation time.
Installs: 443
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Forks: 0
pkg:composer/a4sex/self-signed-token
Requires
- php: ^8.2
- symfony/uid: *
- symfony/validator: *
Requires (Dev)
- phpdocumentor/phpdocumentor: ^3.4
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^9.0
- rector/rector: ^1.0
- symplify/easy-coding-standard: ^12.0
README
Simple, stateless, and secure tokens signed solely with a secret — no database, no network calls.
Table of contents
- About
- Installation
- Quick start
- Token structure
- Time modes and TTL
- Public API
- Token validation
- Manual signature verification
- Helpers and utilities
- Key management (KeyStore)
- Requirements
- License
About
Self‑Signed Token
produces self-signed tokens composed of the following parts:
- an identifier (ID) with optional ID-section data;
- a timestamp and arbitrary payload in the second section;
- a cryptographic signature with an explicit algorithm (except for
md5
); - a meta section (time interpretation type and optional
keyId
).
Validation is fully local using the secret. No DB state is stored or queried. The library also includes a key management (KeyStore) module for generating, rotating, and storing secrets in a file.
Installation
composer require a4sex/self-signed-token
Quick start
use A4Sex\SelfSignedToken;
$tokenService = new SelfSignedToken(
ttl: 60,
secret: 'my-secret',
options: [
'algo' => 'md5', // md5|sha256|sha512|sha3-256|sha3-512
'type' => 'expired', // expired|created
'keyId' => null, // optional key identifier
'bypass' => false, // globally skip checks
]
);
// Create a token
$token = $tokenService->create(payload: ['role','admin']);
// Validate token (signature and expiration)
$isValid = $tokenService->valid($token);
Token structure
<id[:idData...]>.<time[:data...]>.<signSection>.<metaSection>
- ID section:
id[:idData...]
- PAYLOAD section:
time[:data1[:data2...]]
- SIGN section: if the algorithm is
md5
, it contains only<hash>
; otherwise<algo>:<hash>
- META section:
keyId[:type[:version...]]
or justtype
(defaults toexpired
)
Examples
user42.1716309450:role:admin.sha256:1cb7e4d8....created
id1:x.1700000000:foo.sha256:deadbeef.kid-1:created:v1
id2.1700000000.abcd.expired
Time modes and TTL
- expired: the second section stores the expiration moment. If
expire
is not provided on create, it is computed asnow + TTL
. - created: the second section stores the creation time. Expiration is
created + TTL
.
Switch modes via the type
option.
Public API
use A4Sex\SelfSignedToken;
use A4Sex\Entity\Token as TokenEntity;
$t = new SelfSignedToken(ttl: 120, secret: 's3cr3t', options: [
'algo' => 'sha256',
'type' => 'created',
'keyId' => 'kid-1',
]);
// Generate ID (md5 based on secret + randomness)
$id = $t->generateId('prefix-');
// Create token
$token = $t->create(id: $id, expire: null, payload: ['role','admin']);
// Validate: returns token ID or false
$idOrFalse = $t->valid($token, $ignoreSign = false, $ignoreExpires = false);
// Parse into entity
$entity = $t->parse($token); // TokenEntity
// Individual checks
$t->signed($entity); // true|false
$t->expired($entity); // true|false
// Control time/TTL
$t->setCreated(time()); // fix the "current" time
$t->setTtl(300); // change TTL
// Global bypass (disable checks)
$t->setBypass(true);
TokenManager (DTO-based API)
For more structured token creation with comprehensive options validation, use TokenManager
:
use A4Sex\Services\TokenManager;
use A4Sex\DTO\TokenDto;
$manager = new TokenManager(
defaultSecret: 'my-secret',
defaultTtl: 3600
);
// Create with options DTO
$dto = TokenDto::create();
$dto->payload = ['user_id' => 123, 'role' => 'admin'];
$dto->algo = 'sha256';
$dto->type = 'expired';
$dto->keyId = 'key-1';
$dto->version = '1.0';
$token = $manager->create($dto);
// Convenience methods
$token = $manager->createSimple(['user_id' => 456]);
$token = $manager->createWithId('custom-id', ['data' => 'value']);
$token = $manager->createExpiringAt(time() + 1800, ['action' => 'login']);
$token = $manager->createWithAlgorithm('sha512', ['secure' => true]);
$token = $manager->createWithKey('master-key', '2.0', ['access' => 'full']);
Available options in TokenDto
:
id
— explicit token IDexpire
— expiration timestamp (auto-generated if not specified)payload
— array of payload datasecret
— signing secretttl
— time to live in secondsalgo
— signature algorithm (md5
,sha256
,sha512
,sha3-256
,sha3-512
)type
— token type (expired
,created
)keyId
— key identifierversion
— token versioncreated
— creation timestamp (auto-generated for 'created' type if not specified)idData
— additional ID section databypass
— bypass validation flags
Fields available after parse()
:
TokenEntity::id()
— token IDTokenEntity::time()
— time value from the PAYLOAD sectionTokenEntity::payload()
— payload array of stringsTokenEntity::sign()
— signatureTokenEntity::alg()
— signature algorithmTokenEntity::keyId()
—keyId
from META section (if any)TokenEntity::type()
— type (expired
|created
)TokenEntity::version()
— version (if any)
Token validation
$ignoreSignature = false;
$ignoreExpire = false;
$isValid = $tokenService->valid($token, $ignoreSignature, $ignoreExpire);
You can disable all checks globally with setBypass(true)
.
Manual signature verification
use A4Sex\Services\Signer;
$entity = $tokenService->parse($token);
// Canonical string to sign: id:payload[:keyId]:secret
$canonical = $tokenService->signature($entity, 'my-secret');
$ok = Signer::verify($canonical, $entity->sign(), $entity->alg());
Helpers and utilities
Signer: create and verify signatures.
- Supported algorithms:
md5
,sha256
,sha512
,sha3-256
,sha3-512
. Example:
use A4Sex\Services\Signer; $hash = Signer::sign('data', 'sha512'); $ok = Signer::verify('data', $hash, 'sha512');
- Supported algorithms:
TokenSections / entity sections: low-level classes to work with token parts (
TokenIdSection
,TokenPayloadSection
,TokenSignSection
,TokenMetaSection
).TrainParser: build and parse
A:B:C
strings + JSON round-trip helpers.IdGenerator: simple random identifier based on
md5(salt + uniqid(...))
.UuidGenerator: generate
uuid4
,uuid6
,ulid
.A9Generator: fixed-length alphanumeric IDs (A–Z, 0–9) without collisions within a provided list.
Additionally: see docs/styleguide.md
for token style guidance and docs/keystore.md
for key management details.
Key management (KeyStore)
A small file-backed KeyStore to manage signing secrets:
- Key: key model (
id
,secret
,created
,payload[]
). - KeySet: a set of keys keyed by
id
. - KeyStorage: load/save
KeySet
from/to a text file. Line format:ID:SECRET[:CREATED[:PAYLOAD...]]
. Includesreset()
method to clear storage. - KeyGenerator: generate
id
(viaA9Generator
, default length 5) andsecret
(viaIdGenerator
). - KeyManager: high-level operations —
add
,rotate
,revoke
with auto-persist viaKeyStorage
.
Example:
use A4Sex\Key\KeyStorage;
use A4Sex\Key\KeyGenerator;
use A4Sex\KeyManager;
$storage = new KeyStorage(__DIR__ . '/keys.txt');
$manager = new KeyManager($storage);
// Create and add a new key
$generator = new KeyGenerator();
$key = $generator->generate(payload: ['scope','auth']);
$manager->add($key);
// Rotate secret for the existing id
$rotated = $manager->rotate($key->id());
Requirements
- PHP ≥ 8.2
ext-hash
extensionsymfony/uid
package (forUuidGenerator
)
License
MIT licensed. See LICENSE.