Skip to content

Instantly share code, notes, and snippets.

@Jackman3005
Last active March 21, 2023 04:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jackman3005/7c018d62cefeb022743ca4ed5e8e2e4d to your computer and use it in GitHub Desktop.
Save Jackman3005/7c018d62cefeb022743ca4ed5e8e2e4d to your computer and use it in GitHub Desktop.
import crypto from "crypto";
export enum KvdbPermission {
None = 0,
Read = 1 << 1,
Write = 1 << 2,
Delete = 1 << 3,
Enumerate = 1 << 4,
}
interface KvdbToken {
version: number;
expires: number;
permission: number;
prefix: string;
sign: (signingKey: string) => string;
}
export function createKvdbToken(
prefix: string,
ttlSeconds: number,
...permissions: KvdbPermission[]
): KvdbToken {
return {
version: 1,
expires: Math.floor(Date.now() / 1000) + ttlSeconds,
permission: permissions
.map((p) => p.valueOf())
.reduce((p, c) => p | c, KvdbPermission.None.valueOf()),
prefix,
sign(signingKey: string) {
/**
* Token Buffer Bytes Layout:
* 0: version (1 byte)
* 1-4: expiration timestamp (4 bytes - Big Endian Byte Order)
* 5: permission (1 byte)
* 6-: prefix (variable length)
*/
const tokenBuffer = new ArrayBuffer(6 + this.prefix.length);
const dataView = new DataView(tokenBuffer);
dataView.setUint8(0, this.version);
dataView.setUint32(1, this.expires, false); // `false` writes value in big endianness order
dataView.setUint8(5, this.permission);
const byteIndexOfPrefixStart = 6;
for (let i = 0; i < this.prefix.length; i++) {
const byteOffset = i + byteIndexOfPrefixStart;
dataView.setUint8(byteOffset, this.prefix.charCodeAt(i));
}
const base64Token = Buffer.from(tokenBuffer)
.toString("base64url")
.replaceAll("=", "");
const signature = crypto
.createHmac("sha256", signingKey)
.update(new Uint8Array(tokenBuffer))
.digest("base64url")
.replaceAll("=", "");
return `${base64Token}.${signature}`;
},
};
}
@Jackman3005
Copy link
Author

Jackman3005 commented Feb 25, 2023

Here is an example using the code above to create & sign an access token for temporary (60 seconds) write access to keys with the prefix: "users:1:"

const accessToken = createKvdbToken("users:1:", 60, KvdbPermission.Read, KvdbPermission.Write).sign("YOUR_SIGNING_KEY_HERE");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment