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

Avoid using default exports #175

Merged
merged 8 commits into from
Aug 1, 2023
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
37 changes: 26 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ Run `npm install jwt-decode` or `yarn add jwt-decode` to install the library.
### Usage

```js
import jwt_decode from "jwt-decode";
import { jwtDecode } from "jwt-decode";

var token = "eyJ0eXAiO.../// jwt token";
var decoded = jwt_decode(token);
const token = "eyJ0eXAiO.../// jwt token";
const decoded = jwtDecode(token);

console.log(decoded);

Expand All @@ -40,7 +40,7 @@ console.log(decoded);
*/

// decode header by passing in options (useful for when you need `kid` to verify a JWT):
var decodedHeader = jwt_decode(token, { header: true });
const decodedHeader = jwtDecode(token, { header: true });
console.log(decodedHeader);

/* prints:
Expand Down Expand Up @@ -69,35 +69,50 @@ Not adhering to the format will result in a `InvalidTokenError` with one of the
- `Invalid token specified: invalid base64 for part #` => the part could not be base64 decoded (the message should contain the error the base64 decoder gave)
- `Invalid token specified: invalid json for part #` => the part was correctly base64 decoded, however, the decoded value was not valid JSON (the message should contain the error the JSON parser gave)

#### Use with typescript
#### Use with TypeScript

The return type of the `jwt_decode` function is determined by the `header` property of the object passed as the second argument. If omitted (or set to false), it'll use `JwtPayload`, when true it will use `JwtHeader`.
If needed, you can specify what the expected return type should be by passing a type argument to the `jwt_decode` function.
The return type of the `jwtDecode` function is determined by the `header` property of the object passed as the second argument. If omitted (or set to false), it'll use `JwtPayload`, when true it will use `JwtHeader`.
If needed, you can specify what the expected return type should be by passing a type argument to the `jwtDecode` function.

You can extend both `JwtHeader` and `JwtPayload` to include non-standard claims or properties.

```typescript
import jwtDecode from "jwt-decode";
import { jwtDecode } from "jwt-decode";

const token: string = "eyJhsw5c";
const token = "eyJhsw5c";
const decoded = jwtDecode<JwtPayload>(token); // Returns with the JwtPayload type
```

#### Use as a CommonJS package

```javascript
const jwt_decode = require('jwt-decode');
const { jwtDecode } = require('jwt-decode');
...
```

#### Include with a script tag

Copy the file `jwt-decode.js` from the `build/` folder to your project somewhere, then include it like so:
Copy the file `jwt-decode.js` from the root of the `build/` folder to your project somewhere, then include it like so:

```html
<script src="jwt-decode.js"></script>
```

Once this script has loaded, the `jwt_decode` function will be exposed as a global:

```javascript
const token = "eyJhsw5c";
const decoded = jwt_decode(token);
```

Alternatively, if you are using the [Asynchronous Module Definition (AMD) API](https://github.com/amdjs/amdjs-api/blob/master/AMD.md), you can load the same function as follows:

```javascript
define(["jwt_decode"], (jwtDecode) => {
const token = "eyJhsw5c";
const decoded = jwtDecode(token);
});
```

## Feedback

Expand Down
2 changes: 1 addition & 1 deletion lib/base64_url_decode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function b64DecodeUnicode(str: string) {
);
}

export default function(str: string) {
export function base64UrlDecode(str: string) {
frederikprijck marked this conversation as resolved.
Show resolved Hide resolved
let output = str.replace(/-/g, "+").replace(/_/g, "/");
switch (output.length % 4) {
case 0:
Expand Down
6 changes: 0 additions & 6 deletions lib/index.cjs.ts

This file was deleted.

3 changes: 0 additions & 3 deletions lib/index.standalone.ts

This file was deleted.

11 changes: 5 additions & 6 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import base64_url_decode from "./base64_url_decode";
import { base64UrlDecode } from "./base64_url_decode";

export interface JwtDecodeOptions {
header?: boolean;
Expand Down Expand Up @@ -28,12 +28,12 @@ export class InvalidTokenError extends Error {

InvalidTokenError.prototype.name = "InvalidTokenError";

function jwtDecode<T = JwtHeader>(
export function jwtDecode<T = JwtHeader>(
token: string,
options: JwtDecodeOptions & { header: true }
): T;
function jwtDecode<T = JwtPayload>(token: string, options?: JwtDecodeOptions): T;
function jwtDecode(token: string, options?: JwtDecodeOptions) {
export function jwtDecode<T = JwtPayload>(token: string, options?: JwtDecodeOptions): T;
export function jwtDecode(token: string, options?: JwtDecodeOptions) {
if (typeof token !== "string") {
throw new InvalidTokenError("Invalid token specified: must be a string");
}
Expand All @@ -50,7 +50,7 @@ function jwtDecode(token: string, options?: JwtDecodeOptions) {

let decoded: string;
try {
decoded = base64_url_decode(part);
decoded = base64UrlDecode(part);
} catch (e: any) {
throw new InvalidTokenError(
"Invalid token specified: invalid base64 for part #" +
Expand All @@ -74,4 +74,3 @@ function jwtDecode(token: string, options?: JwtDecodeOptions) {
}
}

export default jwtDecode;
1 change: 1 addition & 0 deletions lib/index.umd.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { jwtDecode as default } from './index';
20 changes: 9 additions & 11 deletions rollup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { defineConfig } from "rollup";
import livereload from "rollup-plugin-livereload";
import serve from "rollup-plugin-serve";

const EXPORT_NAME = "jwt-decode";
const isProduction = process.env.NODE_ENV === "production";
const tsPlugin = typescript({
rootDir: "lib",
Expand All @@ -16,8 +15,10 @@ const plugins = [
isProduction && terser(),
];

const input = "lib/index.ts";

export default defineConfig([{
input: "lib/index.standalone.ts",
input: "lib/index.umd.ts",
output: {
name: "jwt_decode",
file: "build/jwt-decode.js",
Expand All @@ -29,24 +30,21 @@ export default defineConfig([{
]
},
{
input: "lib/index.cjs.ts",
output: [{
name: EXPORT_NAME,
input,
output: {
file: "build/cjs/jwt-decode.js",
format: "cjs",
exports: "auto",
sourcemap: true,
}, ],
},
plugins,
},
{
input: "lib/index.ts",
output: [{
name: EXPORT_NAME,
input,
output: {
file: "build/esm/jwt-decode.js",
format: "esm",
sourcemap: true,
}, ],
},
plugins: [!isProduction &&
serve({
contentBase: ["build", "static"],
Expand Down
2 changes: 1 addition & 1 deletion static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ <h2>decoded:</h2>
<pre><code class="js-error3"></code></pre>

<script type="module">
import jwtDecode from "/jwt-decode.esm.js";
import { jwtDecode } from "/esm/jwt-decode.js";
var token =
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIiLCJleHAiOjEzOTMyODY4OTMsImlhdCI6MTM5MzI2ODg5M30.4-iaDojEVl0pJQMjrbM1EzUIfAZgsbK_kgnVyVxFSVo";
var decoded = jwtDecode(token);
Expand Down
32 changes: 16 additions & 16 deletions test/tests.ts
Original file line number Diff line number Diff line change
@@ -1,69 +1,69 @@
import jwt_decode, { InvalidTokenError, JwtPayload } from "./../lib/index";
import { jwtDecode, InvalidTokenError, JwtPayload } from "./../lib/index";
import { describe, expect, it } from "@jest/globals";

var token =
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIiLCJleHAiOjEzOTMyODY4OTMsImlhdCI6MTM5MzI2ODg5M30.4-iaDojEVl0pJQMjrbM1EzUIfAZgsbK_kgnVyVxFSVo";

describe("jwt-decode", function () {
it("should return default and custom claims", function () {
var decoded = jwt_decode<JwtPayload & { foo: string }>(token);
var decoded = jwtDecode<JwtPayload & { foo: string }>(token);
expect(decoded.exp).toEqual(1393286893);
expect(decoded.iat).toEqual(1393268893);
expect(decoded.foo).toEqual("bar");
});

it("should return header information", function () {
var decoded = jwt_decode(token, { header: true });
var decoded = jwtDecode(token, { header: true });
expect(decoded.typ).toEqual("JWT");
expect(decoded.alg).toEqual("HS256");
});

it("should work with utf8 tokens", function () {
var utf8_token =
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiSm9zw6kiLCJpYXQiOjE0MjU2NDQ5NjZ9.1CfFtdGUPs6q8kT3OGQSVlhEMdbuX0HfNSqum0023a0";
var decoded = jwt_decode<JwtPayload & { name: string }>(utf8_token);
var decoded = jwtDecode<JwtPayload & { name: string }>(utf8_token);
expect(decoded.name).toEqual("José");
});

it("should work with binary tokens", function () {
var binary_token =
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiSm9z6SIsImlhdCI6MTQyNTY0NDk2Nn0.cpnplCBxiw7Xqz5thkqs4Mo_dymvztnI0CI4BN0d1t8";
var decoded = jwt_decode<JwtPayload & { name: string }>(binary_token);
var decoded = jwtDecode<JwtPayload & { name: string }>(binary_token);
expect(decoded.name).toEqual("José");
});

it("should work with double padding", function () {
var utf8_token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpvc8OpIiwiaWF0IjoxNTE2MjM5MDIyfQ.7A3F5SUH2gbBSYVon5mas_Y-KCrWojorKQg7UKGVEIA";
var decoded = jwt_decode<JwtPayload & { name: string }>(utf8_token);
var decoded = jwtDecode<JwtPayload & { name: string }>(utf8_token);
expect(decoded.name).toEqual("José");
});

it("should work with single padding", function () {
var utf8_token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpvc8OpZSIsImlhdCI6MTUxNjIzOTAyMn0.tbjJzDAylkKSV0_YGR5xBJBlFK01C82nZPLIcA3JX1g";
var decoded = jwt_decode<JwtPayload & { name: string }>(utf8_token);
var decoded = jwtDecode<JwtPayload & { name: string }>(utf8_token);
expect(decoded.name).toEqual("Josée");
});

it("should throw InvalidTokenError on nonstring", function () {
var bad_token = null;
expect(function () {
jwt_decode(bad_token as any);
jwtDecode(bad_token as any);
}).toThrow(InvalidTokenError);
});

it("should throw InvalidTokenError on string that is not a token", function () {
var bad_token = "fubar";
expect(function () {
jwt_decode(bad_token);
jwtDecode(bad_token);
}).toThrow(InvalidTokenError);
});

it("should throw InvalidTokenErrors when token is null", function () {
var bad_token = null;
expect(function () {
jwt_decode(bad_token as any, { header: true });
jwtDecode(bad_token as any, { header: true });
}).toThrow(
new InvalidTokenError("Invalid token specified: must be a string")
);
Expand All @@ -72,28 +72,28 @@ describe("jwt-decode", function () {
it("should throw InvalidTokenErrors when missing part #1", function () {
var bad_token = ".FAKE_TOKEN";
expect(function () {
jwt_decode(bad_token, { header: true });
jwtDecode(bad_token, { header: true });
}).toThrow(/Invalid token specified: invalid json for part #1/);
});

it("should throw InvalidTokenErrors when part #1 is not valid base64", function () {
var bad_token = "TOKEN";
expect(function () {
jwt_decode(bad_token, { header: true });
jwtDecode(bad_token, { header: true });
}).toThrow(/Invalid token specified: invalid base64 for part #1/);
});

it("should throw InvalidTokenErrors when part #1 is not valid JSON", function () {
var bad_token = "FAKE.TOKEN";
expect(function () {
jwt_decode(bad_token, { header: true });
jwtDecode(bad_token, { header: true });
}).toThrow(/Invalid token specified: invalid json for part #1/);
});

it("should throw InvalidTokenErrors when missing part #2", function () {
var bad_token = "FAKE_TOKEN";
expect(function () {
jwt_decode(bad_token);
jwtDecode(bad_token);
}).toThrow(
new InvalidTokenError("Invalid token specified: missing part #2")
);
Expand All @@ -102,14 +102,14 @@ describe("jwt-decode", function () {
it("should throw InvalidTokenErrors when part #2 is not valid base64", function () {
var bad_token = "FAKE.TOKEN";
expect(function () {
jwt_decode(bad_token);
jwtDecode(bad_token);
}).toThrow(/Invalid token specified: invalid base64 for part #2/);
});

it("should throw InvalidTokenErrors when part #2 is not valid JSON", function () {
var bad_token = "FAKE.TOKEN2";
expect(function () {
jwt_decode(bad_token);
jwtDecode(bad_token);
}).toThrow(/Invalid token specified: invalid json for part #2/);
});
});