Isokey allows you to make and verify self-contained API keys without a database via HMAC/ECDSA signatures.
- Important information such as userID, key expire time, and flags are authenticated and stored within the key.
- Use mutliple secrets
- Invalidate secrets and compromised keys
ks := NewSymKeyService([]byte("super_secure111"))
key := &Key{
UserID: 1,
Expires: time.Now().AddDate(0, 1, 0),
}
digest, err := ks.Sign(key)
if err != nil {
log.Fatalf("Failed to sign key: %v", err)
}
fmt.Printf("Digest is %v\n", digest)
key, err = ks.Verify(digest)
if err != nil {
log.Fatalf("Failed to verify digest: %v", err)
}
// Key authenticated
fmt.Printf("Key: %+v\n", key)
The SecretVersion field is in included in the key object to enable implementors to easily use multiple secrets.
A secret can be decided based on any feature of a key.
ks.GetSecret = function(key *Key) (secret []byte){
if key.SecretVersion == 1 {
return []byte("sec1")
}
return nil
}
All binary values are big endian.
Field | Type |
---|---|
Signature | [16]byte |
Made Time (Unix epoch timestamp) | uint32 |
Expire Time (Unix epoch timestamp) | uint32 |
Secret Version | uint32 |
User ID | uint32 |
Flags | uint32 |
Digests are encoded with Bitcoin's base58 alphabet.
It may seem intuitive to put the signature at the end of the digest. It's located at the beginning as it makes eyeballing different keys easy.
Make your private key
openssl ecparam -genkey -name prime256v1 -outform DER -noout -out privatekey.der
Make your public key
openssl ec -in privatekey.der -inform DER -outform DER -pubout -out publickey.der
privKey, _ = isokey.LoadPrivateKey("priv.key")
ks := NewAsymKeySigner(privKey)
key := &Key{
User: 1,
Expires: time.Now().Add(time.Hour)
}
digest, _ := ks.Sign(key)
fmt.Printf("Digest: %v", digest)
pubKey, err := isokey.LoadPublicKey("pub.key")
if err != nil {
log.Fatalf("Failed to load pubkey: %v", err)
}
kv := NewAsymKeyVerifier(pubKey)
key, err := kv.Verify(digest)
if err != nil {
log.Fatalf("Failed to verify key: %v", err)
}
fmt.Printf("Key verified %+v\n", key)
All binary values are big endian.
Field | Type |
---|---|
R len | uint8 |
R | []byte |
S Len | uint8 |
S | []byte |
Made Time (Unix epoch timestamp) | uint32 |
Expire Time (Unix epoch timestamp) | uint32 |
Secret Version | uint32 |
User ID | uint32 |
Flags | uint32 |
Digests are encoded with Bitcoin's base58 alphabet.
Expired keys always fail to validate.
You can add custom invalidation logic via the Invalidator
field of verifiers.
verifier.Invalidator = function(key *isokey.Key) bool {
// reject keys made before some time
if key.UserID == 10 && key.Made.Before(time.Date(2015, time.November, 10, 23, 0, 0, 0, time.UTC)) {
return true
}
return false
}