@kokuin/token 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,161 @@
1
+ import { type FromSchema } from '@sozai/schema';
2
+ /** @internal */
3
+ export declare const SUPPORTED_ALGORITHMS: readonly ["EdDSA", "ES256"];
4
+ /** @internal */
5
+ export declare const signatureAlgorithmSchema: {
6
+ readonly type: "string";
7
+ readonly enum: readonly ["EdDSA", "ES256"];
8
+ };
9
+ /** @internal */
10
+ export type SignatureAlgorithm = FromSchema<typeof signatureAlgorithmSchema>;
11
+ /** @internal */
12
+ export declare const validateAlgorithm: import("@sozai/schema").Validator<"EdDSA" | "ES256">;
13
+ /** @internal */
14
+ export declare const signedHeaderSchema: {
15
+ readonly type: "object";
16
+ readonly properties: {
17
+ readonly typ: {
18
+ readonly type: "string";
19
+ readonly const: "JWT";
20
+ };
21
+ readonly alg: {
22
+ readonly type: "string";
23
+ readonly enum: readonly ["EdDSA", "ES256"];
24
+ };
25
+ readonly kid: {
26
+ readonly type: "string";
27
+ };
28
+ };
29
+ readonly required: readonly ["typ", "alg"];
30
+ readonly additionalProperties: true;
31
+ };
32
+ /** @internal */
33
+ export type SignedHeader = FromSchema<typeof signedHeaderSchema>;
34
+ /** @internal */
35
+ export declare const validateSignedHeader: import("@sozai/schema").Validator<{
36
+ [x: string]: unknown;
37
+ kid?: string | undefined;
38
+ alg: "EdDSA" | "ES256";
39
+ typ: "JWT";
40
+ }>;
41
+ /** @internal */
42
+ export declare const unsignedHeaderSchema: {
43
+ readonly type: "object";
44
+ readonly properties: {
45
+ readonly typ: {
46
+ readonly type: "string";
47
+ readonly const: "JWT";
48
+ };
49
+ readonly alg: {
50
+ readonly type: "string";
51
+ readonly const: "none";
52
+ };
53
+ };
54
+ readonly required: readonly ["typ", "alg"];
55
+ readonly additionalProperties: true;
56
+ };
57
+ /** @internal */
58
+ export type UnsignedHeader = FromSchema<typeof unsignedHeaderSchema>;
59
+ /** @internal */
60
+ export declare const validateUnsignedHeader: import("@sozai/schema").Validator<{
61
+ [x: string]: unknown;
62
+ alg: "none";
63
+ typ: "JWT";
64
+ }>;
65
+ /** @internal */
66
+ export declare const supportedHeaderSchema: {
67
+ readonly anyOf: readonly [{
68
+ readonly type: "object";
69
+ readonly properties: {
70
+ readonly typ: {
71
+ readonly type: "string";
72
+ readonly const: "JWT";
73
+ };
74
+ readonly alg: {
75
+ readonly type: "string";
76
+ readonly enum: readonly ["EdDSA", "ES256"];
77
+ };
78
+ readonly kid: {
79
+ readonly type: "string";
80
+ };
81
+ };
82
+ readonly required: readonly ["typ", "alg"];
83
+ readonly additionalProperties: true;
84
+ }, {
85
+ readonly type: "object";
86
+ readonly properties: {
87
+ readonly typ: {
88
+ readonly type: "string";
89
+ readonly const: "JWT";
90
+ };
91
+ readonly alg: {
92
+ readonly type: "string";
93
+ readonly const: "none";
94
+ };
95
+ };
96
+ readonly required: readonly ["typ", "alg"];
97
+ readonly additionalProperties: true;
98
+ }];
99
+ };
100
+ /** @internal */
101
+ export type SupportedHeader = FromSchema<typeof supportedHeaderSchema>;
102
+ /** @internal */
103
+ export declare const capabilitySchema: {
104
+ readonly anyOf: readonly [{
105
+ readonly type: "string";
106
+ }, {
107
+ readonly type: "array";
108
+ readonly items: {
109
+ readonly type: "string";
110
+ };
111
+ }];
112
+ };
113
+ /** @internal */
114
+ export declare const signedPayloadSchema: {
115
+ readonly type: "object";
116
+ readonly properties: {
117
+ readonly iss: {
118
+ readonly type: "string";
119
+ };
120
+ readonly sub: {
121
+ readonly type: "string";
122
+ };
123
+ readonly aud: {
124
+ readonly type: "string";
125
+ };
126
+ readonly cap: {
127
+ readonly anyOf: readonly [{
128
+ readonly type: "string";
129
+ }, {
130
+ readonly type: "array";
131
+ readonly items: {
132
+ readonly type: "string";
133
+ };
134
+ }];
135
+ };
136
+ readonly exp: {
137
+ readonly type: "number";
138
+ };
139
+ readonly nbf: {
140
+ readonly type: "number";
141
+ };
142
+ readonly iat: {
143
+ readonly type: "number";
144
+ };
145
+ };
146
+ readonly required: readonly ["iss"];
147
+ readonly additionalProperties: true;
148
+ };
149
+ /** @internal */
150
+ export type SignedPayload = FromSchema<typeof signedPayloadSchema>;
151
+ /** @internal */
152
+ export declare const validateSignedPayload: import("@sozai/schema").Validator<{
153
+ [x: string]: unknown;
154
+ sub?: string | undefined;
155
+ cap?: string | string[] | undefined;
156
+ aud?: string | undefined;
157
+ exp?: number | undefined;
158
+ nbf?: number | undefined;
159
+ iat?: number | undefined;
160
+ iss: string;
161
+ }>;
package/lib/schemas.js ADDED
@@ -0,0 +1,96 @@
1
+ import { createValidator } from '@sozai/schema';
2
+ /** @internal */ export const SUPPORTED_ALGORITHMS = [
3
+ 'EdDSA',
4
+ 'ES256'
5
+ ];
6
+ /** @internal */ export const signatureAlgorithmSchema = {
7
+ type: 'string',
8
+ enum: SUPPORTED_ALGORITHMS
9
+ };
10
+ /** @internal */ export const validateAlgorithm = createValidator(signatureAlgorithmSchema);
11
+ /** @internal */ export const signedHeaderSchema = {
12
+ type: 'object',
13
+ properties: {
14
+ typ: {
15
+ type: 'string',
16
+ const: 'JWT'
17
+ },
18
+ alg: signatureAlgorithmSchema,
19
+ kid: {
20
+ type: 'string'
21
+ }
22
+ },
23
+ required: [
24
+ 'typ',
25
+ 'alg'
26
+ ],
27
+ additionalProperties: true
28
+ };
29
+ /** @internal */ export const validateSignedHeader = createValidator(signedHeaderSchema);
30
+ /** @internal */ export const unsignedHeaderSchema = {
31
+ type: 'object',
32
+ properties: {
33
+ typ: {
34
+ type: 'string',
35
+ const: 'JWT'
36
+ },
37
+ alg: {
38
+ type: 'string',
39
+ const: 'none'
40
+ }
41
+ },
42
+ required: [
43
+ 'typ',
44
+ 'alg'
45
+ ],
46
+ additionalProperties: true
47
+ };
48
+ /** @internal */ export const validateUnsignedHeader = createValidator(unsignedHeaderSchema);
49
+ /** @internal */ export const supportedHeaderSchema = {
50
+ anyOf: [
51
+ signedHeaderSchema,
52
+ unsignedHeaderSchema
53
+ ]
54
+ };
55
+ /** @internal */ export const capabilitySchema = {
56
+ anyOf: [
57
+ {
58
+ type: 'string'
59
+ },
60
+ {
61
+ type: 'array',
62
+ items: {
63
+ type: 'string'
64
+ }
65
+ }
66
+ ]
67
+ };
68
+ /** @internal */ export const signedPayloadSchema = {
69
+ type: 'object',
70
+ properties: {
71
+ iss: {
72
+ type: 'string'
73
+ },
74
+ sub: {
75
+ type: 'string'
76
+ },
77
+ aud: {
78
+ type: 'string'
79
+ },
80
+ cap: capabilitySchema,
81
+ exp: {
82
+ type: 'number'
83
+ },
84
+ nbf: {
85
+ type: 'number'
86
+ },
87
+ iat: {
88
+ type: 'number'
89
+ }
90
+ },
91
+ required: [
92
+ 'iss'
93
+ ],
94
+ additionalProperties: true
95
+ };
96
+ /** @internal */ export const validateSignedPayload = createValidator(signedPayloadSchema);
@@ -0,0 +1,6 @@
1
+ import { fromB64, toB64 } from '@sozai/codec';
2
+ export { fromB64 as decodePrivateKey, toB64 as encodePrivateKey };
3
+ /**
4
+ * Generate a random private key.
5
+ */
6
+ export declare const randomPrivateKey: (seed?: import("@noble/curves/utils.js").TArg<Uint8Array>) => import("@noble/curves/utils.js").TRet<Uint8Array>;
package/lib/signer.js ADDED
@@ -0,0 +1,6 @@
1
+ import { ed25519 } from '@noble/curves/ed25519.js';
2
+ import { fromB64, toB64 } from '@sozai/codec';
3
+ export { fromB64 as decodePrivateKey, toB64 as encodePrivateKey };
4
+ /**
5
+ * Generate a random private key.
6
+ */ export const randomPrivateKey = ed25519.utils.randomSecretKey;
package/lib/time.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Get the current time in seconds since Unix epoch.
3
+ */
4
+ export declare function now(): number;
5
+ /**
6
+ * Options for time-based token validation.
7
+ */
8
+ export type TimeValidationOptions = {
9
+ /** Current time in seconds. Defaults to now(). */
10
+ atTime?: number;
11
+ /** Clock skew tolerance in seconds. Defaults to 0. */
12
+ clockTolerance?: number;
13
+ };
14
+ /**
15
+ * Payload with optional time-based claims.
16
+ */
17
+ export type TimeClaimsPayload = {
18
+ /** Expiration time (seconds since epoch) */
19
+ exp?: number;
20
+ /** Not before time (seconds since epoch) */
21
+ nbf?: number;
22
+ /** Issued at time (seconds since epoch) */
23
+ iat?: number;
24
+ };
25
+ /**
26
+ * Validate time-based claims in a token payload.
27
+ * @throws Error if token is expired or not yet valid
28
+ */
29
+ export declare function assertTimeClaimsValid(payload: TimeClaimsPayload, options?: TimeValidationOptions): void;
package/lib/time.js ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Get the current time in seconds since Unix epoch.
3
+ */ export function now() {
4
+ return Math.floor(Date.now() / 1000);
5
+ }
6
+ /**
7
+ * Validate time-based claims in a token payload.
8
+ * @throws Error if token is expired or not yet valid
9
+ */ export function assertTimeClaimsValid(payload, options = {}) {
10
+ const time = options.atTime ?? now();
11
+ const tolerance = options.clockTolerance ?? 0;
12
+ if (payload.exp != null && payload.exp + tolerance < time) {
13
+ throw new Error('Token expired');
14
+ }
15
+ if (payload.nbf != null && payload.nbf - tolerance > time) {
16
+ throw new Error('Token not yet valid');
17
+ }
18
+ }
package/lib/token.d.ts ADDED
@@ -0,0 +1,53 @@
1
+ import type { DIDCache, DIDResolver } from './cache.js';
2
+ import type { SigningIdentity } from './identity.js';
3
+ import { type SignedPayload } from './schemas.js';
4
+ import { type TimeValidationOptions } from './time.js';
5
+ import type { SignedToken, Token, UnsignedToken, VerifiedToken } from './types.js';
6
+ import { type Verifiers } from './verifier.js';
7
+ export type VerifyTokenOptions = TimeValidationOptions & {
8
+ verifiers?: Verifiers;
9
+ resolver?: DIDResolver;
10
+ cache?: DIDCache;
11
+ };
12
+ export type VerifySignedPayloadInput<Payload extends Record<string, unknown> = Record<string, unknown>> = {
13
+ signature: Uint8Array;
14
+ payload: Payload;
15
+ header: {
16
+ alg?: string;
17
+ kid?: string;
18
+ };
19
+ data: Uint8Array | string;
20
+ verifiers?: Verifiers;
21
+ resolver?: DIDResolver;
22
+ cache?: DIDCache;
23
+ };
24
+ /**
25
+ * Verify the signature of a signed payload and return the public key of the issuer.
26
+ */
27
+ export declare function verifySignedPayload<Payload extends Record<string, unknown> = Record<string, unknown>>(input: VerifySignedPayloadInput<Payload>): Promise<Uint8Array>;
28
+ /**
29
+ * Check if a token is signed.
30
+ */
31
+ export declare function isSignedToken<Payload extends SignedPayload = SignedPayload>(token: unknown): token is SignedToken<Payload>;
32
+ /**
33
+ * Check if a token is unsigned.
34
+ */
35
+ export declare function isUnsignedToken<Payload extends Record<string, unknown>>(token: Token<Payload>): token is UnsignedToken<Payload>;
36
+ /**
37
+ * Check if a token was verified by `verifyToken` in this process.
38
+ * A `verifiedPublicKey` property on a deserialized token is never trusted.
39
+ */
40
+ export declare function isVerifiedToken<Payload extends SignedPayload>(token: unknown): token is VerifiedToken<Payload>;
41
+ /**
42
+ * Create an unsigned token object.
43
+ */
44
+ export declare function createUnsignedToken<Payload extends Record<string, unknown>, Header extends Record<string, unknown> = Record<string, unknown>>(payload: Payload, header?: Header): UnsignedToken<Payload, Header>;
45
+ /**
46
+ * Sign a token object if not already signed.
47
+ */
48
+ export declare function signToken<Payload extends Record<string, unknown>, Header extends Record<string, unknown>>(signer: SigningIdentity, token: Token<Payload, Header>): Promise<SignedToken<Payload, Header>>;
49
+ /**
50
+ * Verify a token is either unsigned or signed with a valid signature.
51
+ * Also validates time-based claims (exp, nbf) if present.
52
+ */
53
+ export declare function verifyToken<Payload extends Record<string, unknown> = Record<string, unknown>>(token: Token<Payload> | string, options?: VerifyTokenOptions): Promise<Token<Payload>>;
package/lib/token.js ADDED
@@ -0,0 +1,181 @@
1
+ import { b64uFromJSON, b64uToJSON, canonicalStringify, fromB64U, fromUTF } from '@sozai/codec';
2
+ import { AttributeKeys, createTracer, SpanNames, withSpan } from '@sozai/otel';
3
+ import { assertType, isType } from '@sozai/schema';
4
+ import { resolveIssuerWithDoc } from './did.js';
5
+ import { validateAlgorithm, validateSignedHeader, validateSignedPayload, validateUnsignedHeader } from './schemas.js';
6
+ import { assertTimeClaimsValid } from './time.js';
7
+ import { getVerifier } from './verifier.js';
8
+ const tokenTracer = createTracer('token');
9
+ // Tokens whose signature was verified in this process. Deserialized JSON can carry a
10
+ // `verifiedPublicKey` property but can never be a member of this set, so verification
11
+ // is only ever skipped for objects produced by `verifyToken` itself.
12
+ const verifiedTokens = new WeakSet();
13
+ /**
14
+ * Verify the signature of a signed payload and return the public key of the issuer.
15
+ */ export async function verifySignedPayload(input) {
16
+ const { signature, payload, header, data, verifiers, resolver, cache } = input;
17
+ assertType(validateSignedPayload, payload);
18
+ const effectiveResolver = cache == null ? resolver : async (did)=>{
19
+ const cached = await cache.get(did);
20
+ if (cached != null) return cached;
21
+ return resolver != null ? resolver(did) : undefined;
22
+ };
23
+ const { alg, publicKey, peer4Doc } = await resolveIssuerWithDoc(payload.iss, {
24
+ kid: header.kid
25
+ }, effectiveResolver);
26
+ const verify = getVerifier(alg, verifiers);
27
+ const message = typeof data === 'string' ? fromUTF(data) : data;
28
+ const verified = await verify(signature, message, publicKey);
29
+ if (!verified) {
30
+ throw new Error('Invalid signature');
31
+ }
32
+ if (cache != null && peer4Doc != null) {
33
+ await cache.set(peer4Doc.shortForm, peer4Doc.doc);
34
+ }
35
+ return publicKey;
36
+ }
37
+ /**
38
+ * Check if a token is signed.
39
+ */ export function isSignedToken(token) {
40
+ const t = token;
41
+ return isType(validateSignedHeader, t.header) && isType(validateSignedPayload, t.payload) && t.signature != null;
42
+ }
43
+ /**
44
+ * Check if a token is unsigned.
45
+ */ export function isUnsignedToken(token) {
46
+ return isType(validateUnsignedHeader, token.header);
47
+ }
48
+ /**
49
+ * Check if a token was verified by `verifyToken` in this process.
50
+ * A `verifiedPublicKey` property on a deserialized token is never trusted.
51
+ */ export function isVerifiedToken(token) {
52
+ return isSignedToken(token) && token.verifiedPublicKey != null && verifiedTokens.has(token);
53
+ }
54
+ /**
55
+ * Create an unsigned token object.
56
+ */ export function createUnsignedToken(payload, header) {
57
+ return {
58
+ header: {
59
+ ...header ?? {},
60
+ typ: 'JWT',
61
+ alg: 'none'
62
+ },
63
+ payload
64
+ };
65
+ }
66
+ /**
67
+ * Sign a token object if not already signed.
68
+ */ export async function signToken(signer, token) {
69
+ return isSignedToken(token) ? token : await signer.signToken(token.payload, {
70
+ header: token.header
71
+ });
72
+ }
73
+ function getVerifiableData(token) {
74
+ const recomputed = `${b64uFromJSON(token.header)}.${b64uFromJSON(token.payload)}`;
75
+ const data = token.data;
76
+ if (data == null || data === recomputed) {
77
+ return recomputed;
78
+ }
79
+ // `data` may use a different JSON serialization of the same header and payload.
80
+ // Accept it only if it decodes to exactly the same values, so the signed bytes
81
+ // can never be decoupled from the payload used for authorization.
82
+ const parts = typeof data === 'string' ? data.split('.') : [];
83
+ if (parts.length === 2) {
84
+ try {
85
+ if (canonicalStringify(b64uToJSON(parts[0])) === canonicalStringify(token.header) && canonicalStringify(b64uToJSON(parts[1])) === canonicalStringify(token.payload)) {
86
+ return data;
87
+ }
88
+ } catch {
89
+ // invalid base64url or JSON in data: fall through to the error below
90
+ }
91
+ }
92
+ throw new Error('Invalid token: data does not match header and payload');
93
+ }
94
+ async function verifyTokenInner(token, options = {}) {
95
+ const { verifiers, resolver, cache, ...timeOptions } = options;
96
+ if (typeof token !== 'string') {
97
+ if (isUnsignedToken(token)) {
98
+ return token;
99
+ }
100
+ if (isVerifiedToken(token)) {
101
+ assertTimeClaimsValid(token.payload, timeOptions);
102
+ return token;
103
+ }
104
+ if (isSignedToken(token)) {
105
+ const data = getVerifiableData(token);
106
+ const verifiedPublicKey = await verifySignedPayload({
107
+ signature: fromB64U(token.signature),
108
+ payload: token.payload,
109
+ header: token.header,
110
+ data,
111
+ verifiers,
112
+ resolver,
113
+ cache
114
+ });
115
+ assertTimeClaimsValid(token.payload, timeOptions);
116
+ const result = {
117
+ ...token,
118
+ data,
119
+ verifiedPublicKey
120
+ };
121
+ verifiedTokens.add(result);
122
+ return result;
123
+ }
124
+ throw new Error('Unsupported token');
125
+ }
126
+ const parts = token.split('.');
127
+ if (parts.length !== 3) {
128
+ throw new Error('Invalid token format: expected 3 parts separated by dots');
129
+ }
130
+ const [encodedHeader, encodedPayload, signature] = parts;
131
+ const header = b64uToJSON(encodedHeader);
132
+ if (header.typ !== 'JWT') {
133
+ throw new Error('Invalid token header type');
134
+ }
135
+ if (header.alg === 'none') {
136
+ return {
137
+ header,
138
+ payload: b64uToJSON(encodedPayload)
139
+ };
140
+ }
141
+ if (isType(validateAlgorithm, header.alg)) {
142
+ if (signature == null) {
143
+ throw new Error('Missing signature for token with signed header');
144
+ }
145
+ const payload = b64uToJSON(encodedPayload);
146
+ const data = `${encodedHeader}.${encodedPayload}`;
147
+ const verifiedPublicKey = await verifySignedPayload({
148
+ signature: fromB64U(signature),
149
+ payload,
150
+ header: header,
151
+ data,
152
+ verifiers,
153
+ resolver,
154
+ cache
155
+ });
156
+ assertTimeClaimsValid(payload, timeOptions);
157
+ const result = {
158
+ data,
159
+ header,
160
+ payload,
161
+ signature,
162
+ verifiedPublicKey
163
+ };
164
+ verifiedTokens.add(result);
165
+ return result;
166
+ }
167
+ throw new Error('Unsupported signature algorithm');
168
+ }
169
+ /**
170
+ * Verify a token is either unsigned or signed with a valid signature.
171
+ * Also validates time-based claims (exp, nbf) if present.
172
+ */ export async function verifyToken(token, options = {}) {
173
+ return withSpan(tokenTracer, SpanNames.TOKEN_VERIFY, {}, async (span)=>{
174
+ const result = await verifyTokenInner(token, options);
175
+ if (isSignedToken(result)) {
176
+ span.setAttribute(AttributeKeys.AUTH_DID, result.payload.iss);
177
+ span.setAttribute(AttributeKeys.AUTH_ALGORITHM, result.header.alg);
178
+ }
179
+ return result;
180
+ });
181
+ }
package/lib/types.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import type { SignedHeader, SignedPayload, UnsignedHeader } from './schemas.js';
2
+ export type SignedToken<Payload extends Record<string, unknown> = Record<string, unknown>, Header extends Record<string, unknown> = Record<string, unknown>> = {
3
+ data: string;
4
+ header: SignedHeader & Header;
5
+ payload: SignedPayload & Payload;
6
+ signature: string;
7
+ };
8
+ export type UnsignedToken<Payload extends Record<string, unknown> = Record<string, unknown>, Header extends Record<string, unknown> = Record<string, unknown>> = {
9
+ data?: string;
10
+ header: UnsignedHeader & Header;
11
+ payload: Payload;
12
+ signature?: undefined;
13
+ };
14
+ export type VerifiedToken<Payload extends Record<string, unknown> = Record<string, unknown>, Header extends Record<string, unknown> = Record<string, unknown>> = SignedToken<Payload, Header> & {
15
+ verifiedPublicKey: Uint8Array;
16
+ };
17
+ export type Token<Payload extends Record<string, unknown> = Record<string, unknown>, Header extends Record<string, unknown> = Record<string, unknown>> = UnsignedToken<Payload, Header> | SignedToken<Payload, Header> | VerifiedToken<Payload, Header>;
package/lib/types.js ADDED
@@ -0,0 +1 @@
1
+ export { };
package/lib/utils.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import type { Token } from './types.js';
2
+ export declare function concatBytes(a: Uint8Array, b: Uint8Array): Uint8Array;
3
+ /**
4
+ * Convert a Token object to its JWT string representation.
5
+ */
6
+ export declare function stringifyToken(token: Token): string;
package/lib/utils.js ADDED
@@ -0,0 +1,19 @@
1
+ import { b64uFromJSON } from '@sozai/codec';
2
+ export function concatBytes(a, b) {
3
+ const out = new Uint8Array(a.length + b.length);
4
+ out.set(a, 0);
5
+ out.set(b, a.length);
6
+ return out;
7
+ }
8
+ /**
9
+ * Convert a Token object to its JWT string representation.
10
+ */ export function stringifyToken(token) {
11
+ const parts = [
12
+ b64uFromJSON(token.header),
13
+ b64uFromJSON(token.payload)
14
+ ];
15
+ if (token.signature != null) {
16
+ parts.push(token.signature);
17
+ }
18
+ return parts.join('.');
19
+ }
@@ -0,0 +1,9 @@
1
+ import type { SignatureAlgorithm } from './schemas.js';
2
+ /** @internal */
3
+ export type Verifier = (signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array) => boolean | Promise<boolean>;
4
+ /** @internal */
5
+ export type Verifiers = Partial<Record<SignatureAlgorithm, Verifier>>;
6
+ /** @internal */
7
+ export declare const defaultVerifiers: Verifiers;
8
+ /** @internal */
9
+ export declare function getVerifier(algorithm: SignatureAlgorithm, verifiers?: Verifiers): Verifier;
@@ -0,0 +1,19 @@
1
+ import { ed25519 } from '@noble/curves/ed25519.js';
2
+ import { p256 } from '@noble/curves/nist.js';
3
+ /** @internal */ export const defaultVerifiers = {
4
+ ES256: (signature, message, publicKey)=>{
5
+ return p256.verify(signature, message, publicKey, {
6
+ lowS: true
7
+ });
8
+ },
9
+ EdDSA: (signature, message, publicKey)=>{
10
+ return ed25519.verify(signature, message, publicKey);
11
+ }
12
+ };
13
+ /** @internal */ export function getVerifier(algorithm, verifiers = {}) {
14
+ const verifier = verifiers[algorithm] ?? defaultVerifiers[algorithm];
15
+ if (verifier == null) {
16
+ throw new Error('Unsupported signature algorithm');
17
+ }
18
+ return verifier;
19
+ }
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@kokuin/token",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "description": "JWT signing and verification",
6
+ "keywords": [
7
+ "json",
8
+ "web",
9
+ "token",
10
+ "jwt",
11
+ "signature"
12
+ ],
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/TairuFramework/kokuin",
16
+ "directory": "packages/token"
17
+ },
18
+ "type": "module",
19
+ "main": "lib/index.js",
20
+ "types": "lib/index.d.ts",
21
+ "exports": {
22
+ ".": "./lib/index.js"
23
+ },
24
+ "files": [
25
+ "lib/*"
26
+ ],
27
+ "sideEffects": false,
28
+ "dependencies": {
29
+ "@sozai/codec": "^0.1.0",
30
+ "@sozai/schema": "^0.1.0",
31
+ "@sozai/otel": "^0.1.0",
32
+ "@noble/ciphers": "^2.1.1",
33
+ "@noble/curves": "^2.0.1",
34
+ "@noble/hashes": "^2.0.0",
35
+ "@scure/base": "^2.2.0"
36
+ },
37
+ "devDependencies": {
38
+ "uint8arrays": "^6.1.1"
39
+ },
40
+ "scripts": {
41
+ "build:clean": "del lib",
42
+ "build:js": "swc src -d ./lib --config-file ../../node_modules/@kigu/dev/swc.json --strip-leading-paths",
43
+ "build:types": "tsc --emitDeclarationOnly --skipLibCheck",
44
+ "build": "pnpm run build:clean && pnpm run build:js && pnpm run build:types",
45
+ "test:types": "tsc --noEmit --skipLibCheck -p tsconfig.test.json",
46
+ "test:unit": "vitest run",
47
+ "test": "pnpm run test:types && pnpm run test:unit"
48
+ }
49
+ }