@benefi/auth 1.0.4 → 1.0.5
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.
- package/README.md +171 -0
- package/dist/src/constants.d.ts +1 -1
- package/dist/src/constants.js +1 -1
- package/dist/src/types.d.ts +1 -1
- package/dist/src/verify.js +1 -1
- package/package.json +1 -1
- package/src/constants.ts +1 -1
- package/src/types.ts +1 -1
- package/src/verify.ts +1 -1
package/README.md
CHANGED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
@benefi/auth
|
|
2
|
+
============
|
|
3
|
+
|
|
4
|
+
**Typed JWT verifier with AWS Secrets Manager rotation support.**
|
|
5
|
+
|
|
6
|
+
This package provides a small helper around `jsonwebtoken` and AWS Secrets Manager to verify JWTs that are signed with a secret stored in Secrets Manager, with built‑in support for secret rotation (tries `AWSCURRENT` first, then `AWSPREVIOUS`) and structured error codes.
|
|
7
|
+
|
|
8
|
+
### Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @benefi/auth
|
|
12
|
+
# or
|
|
13
|
+
yarn add @benefi/auth
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### When to use this package
|
|
17
|
+
|
|
18
|
+
- **You store your JWT secret in AWS Secrets Manager.**
|
|
19
|
+
- **You rotate the secret using version stages (`AWSCURRENT` / `AWSPREVIOUS`).**
|
|
20
|
+
- **You want a simple verifier function that returns typed success/error results instead of throwing.**
|
|
21
|
+
|
|
22
|
+
### Quick start
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { createTokenVerifier } from "@benefi/auth";
|
|
26
|
+
|
|
27
|
+
// Option 1: pass a Secrets Manager secret ID string
|
|
28
|
+
const verifyToken = createTokenVerifier("my-jwt-secret-id");
|
|
29
|
+
|
|
30
|
+
// Option 2: pass a config object
|
|
31
|
+
// const verifyToken = createTokenVerifier({
|
|
32
|
+
// secretId: "my-jwt-secret-id",
|
|
33
|
+
// region: "us-east-1", // optional, defaults to us-east-1
|
|
34
|
+
// });
|
|
35
|
+
|
|
36
|
+
const result = await verifyToken(tokenFromRequest);
|
|
37
|
+
|
|
38
|
+
if (!result.success) {
|
|
39
|
+
// Use result.error.code to decide response status / message
|
|
40
|
+
// e.g. TOKEN_REQUIRED, TOKEN_EXPIRED, INVALID_TOKEN, SECRET_FETCH_FAILURE
|
|
41
|
+
console.error(result.error);
|
|
42
|
+
// return res.status(401).json({ error: result.error });
|
|
43
|
+
} else {
|
|
44
|
+
// Decoded JWT payload with a stable shape
|
|
45
|
+
const { customerId, iat, exp } = result.data;
|
|
46
|
+
// Attach to request context, etc.
|
|
47
|
+
// req.customerId = customerId;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### API
|
|
52
|
+
|
|
53
|
+
#### `createTokenVerifier(secretOrConfig: SecretInput): (token: string) => Promise<VerifyResult>`
|
|
54
|
+
|
|
55
|
+
Creates an async verifier function that you can call with a JWT string.
|
|
56
|
+
|
|
57
|
+
- **`secretOrConfig`** (`SecretInput`)
|
|
58
|
+
- `string`: treated as an AWS Secrets Manager `SecretId`, region defaults to `us-east-1`.
|
|
59
|
+
- `{ secretId: string; region?: string }`: explicitly configure the secret id and AWS region.
|
|
60
|
+
- **Return value**: an async function `verify(token: string): Promise<VerifyResult>`.
|
|
61
|
+
|
|
62
|
+
The returned `verify` function:
|
|
63
|
+
|
|
64
|
+
1. Validates that `token` is a non‑empty string.
|
|
65
|
+
2. Fetches the secret from AWS Secrets Manager:
|
|
66
|
+
- First with version stage `AWSCURRENT`.
|
|
67
|
+
- If verification fails for any reason other than `TokenExpiredError`, retries with `AWSPREVIOUS`.
|
|
68
|
+
3. Verifies the token using `jsonwebtoken`.
|
|
69
|
+
4. Maps the decoded payload into a stable `DecodedJwt` shape:
|
|
70
|
+
- `customerId: string`
|
|
71
|
+
- `iat: number`
|
|
72
|
+
- `exp: number`
|
|
73
|
+
5. Returns a typed `VerifyResult` instead of throwing.
|
|
74
|
+
|
|
75
|
+
### Types
|
|
76
|
+
|
|
77
|
+
These types are re‑exported from the main entry point:
|
|
78
|
+
|
|
79
|
+
- **`SecretInput`**
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
type JwtSecretConfig = {
|
|
83
|
+
secretId: string;
|
|
84
|
+
region?: string;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
type SecretInput = string | JwtSecretConfig;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- **`DecodedJwt`**
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
type DecodedJwt = {
|
|
94
|
+
customerId: string;
|
|
95
|
+
iat: number;
|
|
96
|
+
exp: number;
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
- **`ErrorCode`**
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
type ErrorCode =
|
|
104
|
+
| "TOKEN_REQUIRED"
|
|
105
|
+
| "TOKEN_EXPIRED"
|
|
106
|
+
| "INVALID_TOKEN"
|
|
107
|
+
| "SECRET_FETCH_FAILURE";
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- **`VerifySuccess`**
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
type VerifySuccess = {
|
|
114
|
+
success: true;
|
|
115
|
+
data: DecodedJwt;
|
|
116
|
+
token: string;
|
|
117
|
+
};
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
- **`VerifyError`**
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
type VerifyError = {
|
|
124
|
+
success: false;
|
|
125
|
+
error: {
|
|
126
|
+
code: ErrorCode;
|
|
127
|
+
message: string;
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
- **`VerifyResult`**
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
type VerifyResult = VerifySuccess | VerifyError;
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
You can also import `ERROR_CODES` for convenience:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import { ERROR_CODES } from "@benefi/auth";
|
|
142
|
+
|
|
143
|
+
if (!result.success && result.error.code === ERROR_CODES.TOKEN_EXPIRED) {
|
|
144
|
+
// handle expired token branch
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### AWS configuration
|
|
149
|
+
|
|
150
|
+
This package uses `@aws-sdk/client-secrets-manager` under the hood. Make sure your environment is configured so the AWS SDK can authenticate:
|
|
151
|
+
|
|
152
|
+
- **Environment variables** (e.g. `AWS_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`), or
|
|
153
|
+
- **Instance/role credentials** (e.g. EC2 instance profile, ECS task role, Lambda execution role).
|
|
154
|
+
|
|
155
|
+
If no region is provided in `JwtSecretConfig`, the package defaults to `"us-east-1"` (`DEFAULT_AWS_REGION`).
|
|
156
|
+
|
|
157
|
+
### Error handling
|
|
158
|
+
|
|
159
|
+
The verifier never throws for expected validation failures; instead it returns a `VerifyError`:
|
|
160
|
+
|
|
161
|
+
- **`TOKEN_REQUIRED`** – token is missing, empty, or not a string.
|
|
162
|
+
- **`TOKEN_EXPIRED`** – `jsonwebtoken` reported `TokenExpiredError` while verifying with the current secret.
|
|
163
|
+
- **`INVALID_TOKEN`** – verification failed with both current and previous secrets (bad token, bad signature, wrong algorithm, etc.).
|
|
164
|
+
- **`SECRET_FETCH_FAILURE`** – issues talking to Secrets Manager (e.g. permissions, missing secret, invalid response). The error message will contain the underlying AWS error when available.
|
|
165
|
+
|
|
166
|
+
Use these codes to decide what HTTP status code and response body to send from your API.
|
|
167
|
+
|
|
168
|
+
### License
|
|
169
|
+
|
|
170
|
+
MIT
|
|
171
|
+
|
package/dist/src/constants.d.ts
CHANGED
package/dist/src/constants.js
CHANGED
package/dist/src/types.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export type DecodedJwt = {
|
|
|
9
9
|
exp: number;
|
|
10
10
|
};
|
|
11
11
|
/** Error code returned when verification fails. */
|
|
12
|
-
export type ErrorCode = "TOKEN_REQUIRED" | "TOKEN_EXPIRED" | "INVALID_TOKEN" | "
|
|
12
|
+
export type ErrorCode = "TOKEN_REQUIRED" | "TOKEN_EXPIRED" | "INVALID_TOKEN" | "SECRET_FETCH_FAILURE";
|
|
13
13
|
/** Success result: decoded payload + original token. */
|
|
14
14
|
export type VerifySuccess = {
|
|
15
15
|
success: true;
|
package/dist/src/verify.js
CHANGED
|
@@ -51,7 +51,7 @@ function createTokenVerifier(secretOrConfig) {
|
|
|
51
51
|
return {
|
|
52
52
|
success: false,
|
|
53
53
|
error: {
|
|
54
|
-
code: isAwsError ? "
|
|
54
|
+
code: isAwsError ? "SECRET_FETCH_FAILURE" : "INVALID_TOKEN",
|
|
55
55
|
message: isAwsError
|
|
56
56
|
? (err instanceof Error ? err.message : "Failed to fetch secret")
|
|
57
57
|
: constants_1.TOKEN_INVALID_MESSAGE,
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
package/src/types.ts
CHANGED
package/src/verify.ts
CHANGED
|
@@ -60,7 +60,7 @@ export function createTokenVerifier(secretOrConfig: SecretInput) {
|
|
|
60
60
|
return {
|
|
61
61
|
success: false,
|
|
62
62
|
error: {
|
|
63
|
-
code: isAwsError ? "
|
|
63
|
+
code: isAwsError ? "SECRET_FETCH_FAILURE" : "INVALID_TOKEN",
|
|
64
64
|
message: isAwsError
|
|
65
65
|
? (err instanceof Error ? err.message : "Failed to fetch secret")
|
|
66
66
|
: TOKEN_INVALID_MESSAGE,
|