a4sex / self-signed-token
A simple self-signed token based on a secret string and creation time.
Installs: 460
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
expireis 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()—keyIdfrom 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:Cstrings + 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
KeySetfrom/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,revokewith 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-hashextensionsymfony/uidpackage (forUuidGenerator)
License
MIT licensed. See LICENSE.