Example key:
mycompany_BRTRKFsL_51FwqftsmMDHHbJAMEXXHCgG
Seam-style API Keys have many advantages:
- Double clicking the api key selects the entire api key
- The alphabet is standard across languages thanks to the base58 RFC and its usage in cryptocurrencies
- They are shorter than hex and base32 api keys
- They have prefixes allowing secret scanning by github
- They have a hashed component so the server doesn't need to store the api key (reducing attack surface)
- They have unhashed short tokens which can be mutually used by the server and key bearer/customer to identify the api key
- They default to roughly the same number of entropy bits as UUIDv4
Seam-style api keys look like this:
mycompany_BRTRKFsL_51FwqftsmMDHHbJAMEXXHCgG
Let's break down each component of the API key...
mycompany ..._... BRTRKFsL ..._... 51FwqftsmMDHHbJAMEXXHCgG
^ ^ ^
Prefix Short Token Long Token
- The Prefix is used to identify the company or service creating the API Key. This is very helpful in secret scanning.
- The Short Token is stored by both the server and the key bearer/customer, it can be used to identify an API key in logs or displayed on a customer's dashboard. A token can be blocklisted by its short token.
- The Long Token is how we authenticate this key. The long token is never stored
on the server, but a hash of it is stored on the server. When we receive an
incoming request, we search our database for
short_token
andhash(long_token)
.
import { generateAPIKey } from "prefixed-api-key"
const key = await generateAPIKey({ keyPrefix: 'mycompany' })
// Store the key.longTokenHash and key.shortToken in your database and give
// key.token to your customer.
console.log(key)
/*
{
shortToken: 'BRTRKFsL',
longToken: '51FwqftsmMDHHbJAMEXXHCgG',
longTokenHash: 'd70d981d87b449c107327c2a2afbf00d4b58070d6ba571aac35d7ea3e7c79f37',
token: 'mycompany_BRTRKFsL_51FwqftsmMDHHbJAMEXXHCgG'
}
*/
import {
hashLongToken,
extractLongToken,
extractShortToken,
checkAPIKey,
getTokenComponents,
} from "prefixed-api-key"
hashLongToken("51FwqftsmMDHHbJAMEXXHCgG")
// "d70d981d87b449c107327c2a2afbf00d4b58070d6ba571aac35d7ea3e7c79f37"
extractLongToken("mycompany_BRTRKFsL_51FwqftsmMDHHbJAMEXXHCgG")
// "51FwqftsmMDHHbJAMEXXHCgG"
})
extractShortToken("mycompany_BRTRKFsL_51FwqftsmMDHHbJAMEXXHCgG")
// "BRTRKFsL"
getTokenComponents("mycompany_BRTRKFsL_51FwqftsmMDHHbJAMEXXHCgG")
/*
{
shortToken: 'BRTRKFsL',
longToken: '51FwqftsmMDHHbJAMEXXHCgG',
longTokenHash: 'd70d981d87b449c107327c2a2afbf00d4b58070d6ba571aac35d7ea3e7c79f37',
token: 'mycompany_BRTRKFsL_51FwqftsmMDHHbJAMEXXHCgG'
}
*/
await checkAPIKey(
"mycompany_BRTRKFsL_51FwqftsmMDHHbJAMEXXHCgG",
"d70d981d87b449c107327c2a2afbf00d4b58070d6ba571aac35d7ea3e7c79f37"
)
// true