diff --git a/src/index.test.ts b/src/index.test.ts index a278a7d..5661f89 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -183,6 +183,53 @@ describe('CAT', () => { }); }); + test('can generate a token with no padding', async () => { + const generator = new CAT({ + keys: { + Symmetric256: Buffer.from( + '403697de87af64611c1d32a05dab0fe1fcb715a86ab435f1ec99192d79569388', + 'hex' + ) + } + }); + const base64encoded = await generator.generateFromJson( + { + iss: 'eyevinn', + exp: 1742984408, + iat: 1742980808, + cti: '66400ca63ab2c267cc0d874cc5f9a378', + catv: 1 + }, + { + type: 'mac', + alg: 'HS256', + kid: 'Symmetric256' + } + ); + console.log(base64encoded); + expect(base64encoded).not.toContain('='); + const validator = new CAT({ + keys: { + Symmetric256: Buffer.from( + '403697de87af64611c1d32a05dab0fe1fcb715a86ab435f1ec99192d79569388', + 'hex' + ) + } + }); + const result = await validator.validate(base64encoded!, 'mac', { + issuer: 'eyevinn' + }); + expect(result.error).not.toBeDefined(); + expect(result.cat).toBeDefined(); + expect(result.cat!.claims).toEqual({ + iss: 'eyevinn', + exp: 1742984408, + iat: 1742980808, + cti: '66400ca63ab2c267cc0d874cc5f9a378', + catv: 1 + }); + }); + test('can validate a MAC:ed token with standard claims', async () => { const base64encoded = '0YRDoQEFoQRMU3ltbWV0cmljMjU2eDZkOTAxMDNhMTAxNzU2MzZmNjE3MDNhMmYyZjYxNzMyZTY1Nzg2MTZkNzA2YzY1MmU2MzZmNmRYIDL8dIteq8pMXXX9oL4eo2NX1kQUaselV6p/JHSEVXWX'; diff --git a/src/index.ts b/src/index.ts index 86f7f4e..2b97154 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,7 @@ import { CommonAccessTokenFactory } from './cat'; import { KeyNotFoundError } from './errors'; -import { generateRandomHex, toBase64 } from './util'; +import { generateRandomHex, toBase64NoPadding } from './util'; export { CommonAccessToken } from './cat'; export { CommonAccessTokenRenewal } from './catr'; @@ -239,7 +239,7 @@ export class CAT { if (!cat.raw) { throw new Error('Failed to MAC token'); } - return toBase64(cat.raw); + return toBase64NoPadding(cat.raw); } } @@ -295,7 +295,7 @@ export class CAT { if (!cat.raw) { throw new Error('Failed to MAC token'); } - return toBase64(cat.raw); + return toBase64NoPadding(cat.raw); } } @@ -329,6 +329,6 @@ export class CAT { if (!newCat.raw) { throw new Error('Failed to MAC token'); } - return toBase64(newCat.raw); + return toBase64NoPadding(newCat.raw); } } diff --git a/src/util.ts b/src/util.ts index d25f21b..f4892b2 100644 --- a/src/util.ts +++ b/src/util.ts @@ -24,3 +24,13 @@ export function toHex(input: Buffer): string { .map((byte) => byte.toString(16).padStart(2, '0')) .join(''); } + +/** + * Convert a buffer to base64 string without padding + * @param input Buffer to convert + * @returns Base64 string without padding + */ +export function toBase64NoPadding(input: Buffer): string { + const base64 = toBase64(input); + return base64.replace(/=+$/, ''); +} diff --git a/src/validators/http.ts b/src/validators/http.ts index 2f3c8ac..bbb9514 100644 --- a/src/validators/http.ts +++ b/src/validators/http.ts @@ -20,6 +20,7 @@ import { CommonAccessTokenDict, CommonAccessTokenFactory } from '../cat'; import { ICTIStore } from '../stores/interface'; import { ITokenLogger } from '../loggers/interface'; import { CatIfDictValue } from '../catif'; +import { toBase64NoPadding } from '../util'; interface HttpValidatorKey { kid: string; @@ -388,7 +389,7 @@ export class HttpValidator { this.opts.alg || 'HS256', { addCwtTag: true } ); - const newToken = newCat.raw?.toString('base64'); + const newToken = toBase64NoPadding(newCat.raw!); const encodedToken = encodeURIComponent(newToken!); const newUrl = new URL(value[header][0] + encodedToken); response.setHeader(header, newUrl.toString());