Skip to content

Commit 77f8c8e

Browse files
committed
Update parseBearerToken function to handle undefined authorization and improve error messaging; update tests accordingly
1 parent 5dd3bfd commit 77f8c8e

File tree

8 files changed

+66
-42
lines changed

8 files changed

+66
-42
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 0.3.1 (jul 18th 2025)
2+
3+
- Improve parseBearerToken() function to handle undefined authorization properly in typescript
4+
15
# 0.3.0 (jul 17th 2025)
26

37
- Add parseBearerToken() function to extract access token from authorization header

README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,10 @@ function verify( token: string,
359359
* This function validates that the authorization header follows the correct Bearer token format
360360
* ("Bearer <token>") and extracts the token portion for further processing.
361361
*
362-
* @param {string} authorization - The Authorization header value from an HTTP request
362+
* @param {string | undefined} authorization - The Authorization header value from an HTTP request
363363
* @returns {string} The extracted JWT token as a string
364-
* @throws {Error} Will throw an error if the authorization header is empty or not in the format 'Bearer <token>'
364+
* @throws {Error} Will throw an error if the authorization parameter is undefined
365+
* @throws {Error} Will throw an error if the format is invalid
365366
*
366367
* @example
367368
* ```typescript
@@ -375,19 +376,20 @@ function verify( token: string,
375376
* const token2 = parseBearerToken(headerWithSpaces);
376377
* // Returns: "token123"
377378
*
378-
* // Invalid headers - these will throw errors
379+
* // Invalid headers - these will throw specific errors
379380
* try {
380-
* parseBearerToken("Basic dXNlcjpwYXNz"); // Throws Error
381-
* parseBearerToken("Bearer"); // Throws Error
382-
* parseBearerToken("Bearer "); // Throws Error
383-
* parseBearerToken(""); // Throws Error
381+
* parseBearerToken(undefined); // Throws: "Authorization header is missing"
382+
* parseBearerToken(""); // Throws: "Authorization header must be in the format 'Bearer <token>'"
383+
* parseBearerToken("Basic dXNlcjpwYXNz"); // Throws: "Authorization header must be in the format 'Bearer <token>'"
384+
* parseBearerToken("Bearer"); // Throws: "Authorization header must be in the format 'Bearer <token>'"
385+
* parseBearerToken("Bearer "); // Throws: "Authorization header must be in the format 'Bearer <token>'"
384386
* } catch (error) {
385-
* console.error('Invalid authorization header:', error.message);
387+
* console.error('Authorization error:', error.message);
386388
* }
387389
* ```
388390
*
389391
*/
390-
function parseBearerToken(authorization: string): string;
392+
function parseBearerToken(authorization: string | undefined): string;
391393

392394
```
393395

dist/passken.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ declare function randomPwd(opts?: Partial<Options>): string;
6060
declare function randomSecret(length?: number): string;
6161
declare function sign(iss: number | string, duration: number, type: Type, b64Keys: string[]): string;
6262
declare function verify(token: string, b64Keys: string[], ignoreExpiration?: boolean): Payload;
63-
declare function parseBearerToken(authorization: string): string;
63+
declare function parseBearerToken(authorization: string | undefined): string;
6464

6565
export {
6666
getSaltRounds,

dist/passken.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,11 @@ function verify(token, b64Keys, ignoreExpiration = false) {
228228
return payload;
229229
}
230230
const BEARER_TOKEN_ERROR_MESSAGE = "Authorization header must be in the format 'Bearer <token>'";
231+
const MISSING_AUTHORIZATION_ERROR_MESSAGE = "Authorization header is missing";
231232
function parseBearerToken(authorization) {
232-
if (!(authorization === null || authorization === void 0 ? void 0 : authorization.startsWith("Bearer ")))
233+
if (!authorization)
234+
throw new Error(MISSING_AUTHORIZATION_ERROR_MESSAGE);
235+
if (!authorization.startsWith("Bearer "))
233236
throw new Error(BEARER_TOKEN_ERROR_MESSAGE);
234237
const parts = authorization.split(" ").filter(part => part.length > 0);
235238
if (parts.length < 2 || !parts[1])

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@dwtechs/passken",
3-
"version": "0.3.0",
3+
"version": "0.3.1",
44
"description": "Open source password and JWT management library for Node.js to create, encrypt and compare safely.",
55
"keywords": [
66
"passwords",

src/jwt.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,10 @@ function verify(token: string, b64Keys: string[], ignoreExpiration = false): Pay
154154
* This function validates that the authorization header follows the correct Bearer token format
155155
* ("Bearer <token>") and extracts the token portion for further processing.
156156
*
157-
* @param {string} authorization - The Authorization header value from an HTTP request
157+
* @param {string | undefined} authorization - The Authorization header value from an HTTP request
158158
* @returns {string} The extracted JWT token as a string
159-
* @throws {Error} Will throw an error if the authorization header is empty or not in the format 'Bearer <token>'
159+
* @throws {Error} Will throw an error if the authorization parameter is undefined
160+
* @throws {Error} Will throw an error if the format is invalid
160161
*
161162
* @example
162163
* ```typescript
@@ -170,23 +171,28 @@ function verify(token: string, b64Keys: string[], ignoreExpiration = false): Pay
170171
* const token2 = parseBearerToken(headerWithSpaces);
171172
* // Returns: "token123"
172173
*
173-
* // Invalid headers - these will throw errors
174+
* // Invalid headers - these will throw specific errors
174175
* try {
175-
* parseBearerToken("Basic dXNlcjpwYXNz"); // Throws Error
176-
* parseBearerToken("Bearer"); // Throws Error
177-
* parseBearerToken("Bearer "); // Throws Error
178-
* parseBearerToken(""); // Throws Error
176+
* parseBearerToken(undefined); // Throws: "Authorization header is missing"
177+
* parseBearerToken(""); // Throws: "Authorization header must be in the format 'Bearer <token>'"
178+
* parseBearerToken("Basic dXNlcjpwYXNz"); // Throws: "Authorization header must be in the format 'Bearer <token>'"
179+
* parseBearerToken("Bearer"); // Throws: "Authorization header must be in the format 'Bearer <token>'"
180+
* parseBearerToken("Bearer "); // Throws: "Authorization header must be in the format 'Bearer <token>'"
179181
* } catch (error) {
180-
* console.error('Invalid authorization header:', error.message);
182+
* console.error('Authorization error:', error.message);
181183
* }
182184
* ```
183185
*
184186
*/
185187
const BEARER_TOKEN_ERROR_MESSAGE = "Authorization header must be in the format 'Bearer <token>'";
188+
const MISSING_AUTHORIZATION_ERROR_MESSAGE = "Authorization header is missing";
186189

187-
function parseBearerToken(authorization: string): string {
190+
function parseBearerToken(authorization: string | undefined): string {
188191

189-
if (!authorization?.startsWith("Bearer "))
192+
if (!authorization)
193+
throw new Error(MISSING_AUTHORIZATION_ERROR_MESSAGE);
194+
195+
if (!authorization.startsWith("Bearer "))
190196
throw new Error(BEARER_TOKEN_ERROR_MESSAGE);
191197

192198
// Split by spaces and filter out empty strings to handle multiple spaces
@@ -199,10 +205,15 @@ function parseBearerToken(authorization: string): string {
199205

200206
}
201207

202-
203-
// Generate a random index based on the array length
208+
// Generate a random index based on an array length
204209
function randomPick(array: string[]): number {
205210
return Math.floor(Math.random() * array.length);
206211
}
207212

208-
export { sign, verify, parseBearerToken, BEARER_TOKEN_ERROR_MESSAGE };
213+
export {
214+
sign,
215+
verify,
216+
parseBearerToken,
217+
BEARER_TOKEN_ERROR_MESSAGE,
218+
MISSING_AUTHORIZATION_ERROR_MESSAGE,
219+
};

src/passken.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ declare function randomPwd(opts?: Partial<Options>): string;
3434
declare function randomSecret(length?: number): string;
3535
declare function sign(iss: number | string, duration: number, type: Type, b64Keys: string[]): string;
3636
declare function verify(token: string, b64Keys: string[], ignoreExpiration?: boolean): Payload;
37-
declare function parseBearerToken(authorization: string): string;
37+
declare function parseBearerToken(authorization: string | undefined): string;
3838

3939
export {
4040
getSaltRounds,

tests/parseBearerToken.test.js

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { parseBearerToken, BEARER_TOKEN_ERROR_MESSAGE } from "../dist/passken.js";
1+
import { parseBearerToken, BEARER_TOKEN_ERROR_MESSAGE, MISSING_AUTHORIZATION_ERROR_MESSAGE } from "../dist/passken.js";
22

33
describe("parseBearerToken", () => {
44

@@ -50,12 +50,27 @@ describe("parseBearerToken", () => {
5050
});
5151
});
5252

53-
describe("Invalid Bearer tokens - should throw errors", () => {
54-
test("throws error for empty string", () => {
53+
describe("Missing authorization header - should throw specific errors", () => {
54+
test("throws specific error for undefined authorization", () => {
55+
expect(() => {
56+
parseBearerToken(undefined);
57+
}).toThrow(MISSING_AUTHORIZATION_ERROR_MESSAGE);
58+
});
59+
60+
test("throws specific error for null authorization", () => {
61+
expect(() => {
62+
parseBearerToken(null);
63+
}).toThrow(MISSING_AUTHORIZATION_ERROR_MESSAGE);
64+
});
65+
66+
test("throws specific error for empty authorization", () => {
5567
expect(() => {
5668
parseBearerToken("");
57-
}).toThrow(BEARER_TOKEN_ERROR_MESSAGE);
69+
}).toThrow(MISSING_AUTHORIZATION_ERROR_MESSAGE);
5870
});
71+
});
72+
73+
describe("Invalid Bearer tokens - should throw format errors", () => {
5974

6075
test("throws error for Bearer without token", () => {
6176
expect(() => {
@@ -105,18 +120,6 @@ describe("parseBearerToken", () => {
105120
}).toThrow(BEARER_TOKEN_ERROR_MESSAGE);
106121
});
107122

108-
test("throws error for null input", () => {
109-
expect(() => {
110-
parseBearerToken(null);
111-
}).toThrow();
112-
});
113-
114-
test("throws error for undefined input", () => {
115-
expect(() => {
116-
parseBearerToken(undefined);
117-
}).toThrow();
118-
});
119-
120123
test("throws error for Bearer with tab character", () => {
121124
expect(() => {
122125
parseBearerToken("Bearer\tsometoken");
@@ -186,4 +189,5 @@ describe("parseBearerToken", () => {
186189
});
187190
});
188191
});
192+
189193
});

0 commit comments

Comments
 (0)