Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TS type definitions #77

Merged
merged 14 commits into from
Apr 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"sourceType": "module"
},
"rules": {
"curly": [
2
],
"eol-last": ["error", "always"],
"indent": [
2,
2
],
"linebreak-style": [
2,
"unix"
],
"new-cap": [
0
],
"no-trailing-spaces": [
2
],
"quotes": [
2,
"single"
],
"semi": [
2,
"always"
],
"wrap-iife": [
2,
"outside"
],
"brace-style": 2,
"block-spacing": [
2,
"always"
],
"keyword-spacing": [2, {"before": true, "after": true, "overrides": {}}],
"space-before-blocks": 2,
"space-before-function-paren": [2, {"anonymous": "always", "named": "never"}],
"comma-spacing": [2, {"before": false, "after": true}],
"comma-style": [2, "last"],
"array-bracket-spacing": [2, "never"],
"no-spaced-func": [2],
"space-in-parens": [2, "never"],
"space-infix-ops": 2
},
"plugins": [
"@typescript-eslint"
],
"extends": [
"plugin:@typescript-eslint/recommended"
],
"ignorePatterns": ["*.js", "test/*.js"]
}
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
language: node_js
node_js:
- '6'
- '8'
- '10'
- '12'
- '14'
script:
- npm test
branches:
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# nJwt Change Log

### 1.1.0

* [#77](https://github.com/jwtk/njwt/pull/77) Adds TypeScript type definitions.

### 1.0.0

* Removed support for older Node versions. Now requires Node 6+.
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,18 @@ none | No digital signature or MAC value included
The following features are not yet supported by this library:

* Encrypting the JWT (aka JWE)

## TypeScript usage

This package includes TypeScript definitions for library interface. They can be used as follows:

```typescript
import { Jwt, create } from 'njwt';
import crypto = require('crypto');

const signingKey: Buffer = crypto.randomBytes(256); // Create a highly random byte array of 256 bytes
const claims = {
iss: 'http://myapp.com/', // The URL of your service
};
const jwt: Jwt = create(claims, signingKey);
```
96 changes: 96 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/// <reference types="node" />
import { KeyObject } from 'crypto';

declare type JSONValue = string | number | boolean | null | JSONValue[] | JSONMap;
declare type JSONMap = {[key: string]: JSONValue};

declare interface JwtHeaderOptions {
alg: string;
typ?: string;
kid?: string;
jku?: string;
x5c?: string;
x5u?: string;
x5t?: string;
'x5t#s256'?: string;
}

declare type SupportedAlgorithms =
'HS256' |
'HS384' |
'HS512' |
'RS256' |
'RS512' |
'ES256' |
'ES384' |
'ES512' |
'none';

declare type IsSupportedAlg = (algName: string | SupportedAlgorithms) => boolean;
declare type KeyResolverCallback = (err: Error | null, signingKey: string | Buffer) => Jwt | undefined | never;

export declare type KeyResolver = (kid: string, cb: KeyResolverCallback) => Jwt | undefined | never;

export declare function Jwt(claims: JSONMap, enforceDefaultFields: boolean): Jwt;
export declare class Jwt {
constructor(claims: JSONMap, enforceDefaultFields: boolean);
header: JwtHeader;
body: JwtBody;
setClaim(claim: string, value: JSONValue): Jwt;
setHeader(param: string, value: string): Jwt;
setJti(jti: string): Jwt;
setSubject(sub: string): Jwt;
setIssuer(iss: string): Jwt;
setIssuedAt(iat: number): Jwt;
setExpiration(exp: Date | number | string): Jwt;
setNotBefore(nbf: Date | number | string): Jwt;
setSigningKey(key: string | Buffer): Jwt;
signingKey: string | Buffer;
setSigningAlgorithm(alg: string): Jwt;
sign(payload: string | Buffer | JSONMap, algorithm: string, cryptoInput: string | Buffer | KeyObject): string;
isSupportedAlg: IsSupportedAlg;
compact(): string;
signature: string;
toString(): string;
isExpired(): boolean;
isNotBefore(): boolean;
}
export declare function JwtBody(claims: JSONMap): JwtBody;
export declare class JwtBody {
constructor(claims: JSONMap);
toJSON(): JSONMap;
compact(): string;
}
export declare function JwtHeader(header: JwtHeaderOptions): JwtHeader;
export declare class JwtHeader {
constructor(header: JwtHeaderOptions);
typ: string;
alg: string;
reservedKeys: string[];
compact(): string;
}

export declare function Verifier(): Verifier;
export declare class Verifier {
setSigningAlgorithm(alg: string): Verifier | never;
signingAlgorithm: SupportedAlgorithms;
setSigningKey(keyStr: string | Buffer): Verifier;
signingKey: string | Buffer;
setKeyResolver(keyResolver: KeyResolver): void;
keyResolver: KeyResolver;
isSupportedAlg: IsSupportedAlg;
/**
* Synchronous mode.
*/
verify(jwtString: string | Buffer): Jwt | never;
/**
* Async mode.
*/
verify(jwtString: string | Buffer, cb: (err: Error | null, verifiedJwt: Jwt) => void): void | never;
withKeyResolver(keyResolver: KeyResolver): Verifier;
}
export declare function base64urlEncode(number: number | string): Buffer;
export declare function base64urlUnescape(str: string): string;
export declare function verify(jwtTokenString: string | Buffer, signingKey?: string | Buffer, alg?: string, callback?: KeyResolver): undefined | Jwt | never;
export declare function createVerifier(): Verifier;
export declare function create(claimsOrSecret: JSONMap | string | Buffer, ...args: unknown[]): Jwt;
27 changes: 24 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
{
"name": "njwt",
"version": "1.0.0",
"version": "1.1.0",
"description": "JWT Library for Node.js",
"main": "index.js",
"types": "index.d.ts",
"scripts": {
"lint": "eslint .",
"test": "istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly test/ -- -R spec --no-timeouts; cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js; rm -rf ./coverage",
"test-watch": "mocha --timeout=5000 --reporter dot --check-leaks -w ./*.js test/ ",
"test-debug": "mocha --timeout=5000 --debug --reporter dot --check-leaks -w ./*.js test/ ",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --timeout=5000 --reporter dot --check-leaks test/"
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --timeout=5000 --reporter dot --check-leaks test/",
"test-types": "tsd"
},
"repository": {
"type": "git",
Expand All @@ -23,16 +26,34 @@
},
"homepage": "https://github.com/jwtk/njwt",
"dependencies": {
"@types/node": "^15.0.1",
"ecdsa-sig-formatter": "^1.0.5",
"uuid": "^3.3.2"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
"chai": "^4.2.0",
"coveralls": "^3.0.3",
"eslint": "^7.25.0",
"istanbul": "^0.4.5",
"jsonwebtoken": "^8.5.0",
"jwt-simple": "^0.5.5",
"mocha": "^6.0.2",
"secure-random": "^1.1.1"
"secure-random": "^1.1.1",
"tsd": "^0.14.0",
"typescript": "^4.2.4"
},
"tsd": {
"directory": "test/types",
"compilerOptions": {
"strict": true,
"baseUrl": "./",
"paths": {
"njwt": [
"."
]
}
}
}
}
35 changes: 35 additions & 0 deletions test/types/jwt.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Jwt, JwtBody, JwtHeader, create, JSONMap, base64urlEncode, base64urlUnescape } from 'njwt';
import { expectType, expectError } from 'tsd';


expectType<Jwt>(Jwt({}, false));
expectType<Jwt>(new Jwt({}, false));
expectType<Jwt>(create({}));
expectType<Jwt>(create({}, 'signingKey'));
expectType<Jwt>(create('signingKey'));
expectType<Jwt>(create(Buffer.from([])));

const jwt = new Jwt({}, true);
expectType<string>(jwt.sign({}, 'alg', 'signingKeyValue'));
expectType<Jwt>(jwt.setHeader('headerParam', 'headerValue'));
expectType<Jwt>(jwt.setIssuedAt(123456));
expectType<Jwt>(jwt.setIssuer('atko'));
expectType<Jwt>(jwt.setJti('uuid'));
expectType<Jwt>(jwt.setNotBefore(new Date()));
expectType<Jwt>(jwt.setSigningAlgorithm('sha'));
expectType<Jwt>(jwt.setSigningKey(Buffer.from([])));
expectType<Jwt>(jwt.setSubject('userid'));
expectType<string>(jwt.toString());

const jwtBody = new JwtBody({});
expectType<string>(jwtBody.compact());
expectType<JSONMap>(jwtBody.toJSON());

const jwtHeader = new JwtHeader({alg: 'HS256'});
expectType<string>(jwtHeader.compact());

// alg property is required
expectError(new JwtHeader({}));

expectType<Buffer>(base64urlEncode('atob'));
expectType<string>(base64urlUnescape('btoa=='));
36 changes: 36 additions & 0 deletions test/types/verify.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* eslint-disable no-unused-vars */

import { Jwt, Verifier, verify, createVerifier } from 'njwt';
import { expectType, expectError } from 'tsd';

expectType<Verifier>(Verifier());
const verifier = new Verifier();
expectType<Verifier>(verifier.setSigningAlgorithm('none'));

expectType<void>(verifier.setKeyResolver(function (keyId: string, callback: (err: Error | null, resolvedKey: string) => Jwt | undefined) {
return callback(null, 'resolvedKey');
}));

// eslint-disable-next-line @typescript-eslint/no-unused-vars
expectType<void>(verifier.setKeyResolver(function (keyId: string, callback: (err: Error | null, resolvedKey: string) => Jwt | undefined) {
throw new Error();
}));

expectType<Verifier>(verifier.withKeyResolver(function (keyId: string, callback: (err: Error | null, resolvedKey: string) => Jwt | undefined) {
return callback(null, 'resolvedKey');
}));

// callback signature is enforced
expectError<Verifier>(verifier.withKeyResolver(function (keyId: string, callback: (err: string | null, resolvedKey: string) => Jwt | undefined) {
return callback(null, 'resolvedKey');
}));

expectType<Verifier>(verifier.setSigningKey(Buffer.from([])));

expectType<Jwt>(verifier.verify('tokenString'));
expectType<void>(verifier.verify('tokenString', function (err: Error | null, token: Jwt) {
console.log(token);
}));

expectType<Jwt | undefined>(verify(Buffer.from('tokenString')));
expectType<Verifier>(createVerifier());
Loading