@stacksjs/auth 0.72.103 → 0.73.1
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/dist/request-token.d.ts +14 -1
- package/dist/request-token.js +1 -1
- package/dist/tokens.d.ts +0 -15
- package/dist/tokens.js +11 -11
- package/package.json +3 -3
package/dist/request-token.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare function requestToken(request: TokenBearingRequest | null | undefined): string | null;
|
|
1
2
|
/**
|
|
2
3
|
* The access token a request carries, from the Authorization header or the
|
|
3
4
|
* auth cookie.
|
|
@@ -13,4 +14,16 @@
|
|
|
13
14
|
*
|
|
14
15
|
* The header is checked first, so an API client behaves exactly as before.
|
|
15
16
|
*/
|
|
16
|
-
|
|
17
|
+
/**
|
|
18
|
+
* What this needs off a request, which is deliberately little.
|
|
19
|
+
*
|
|
20
|
+
* Both members are optional because the function is handed two different
|
|
21
|
+
* shapes: a Stacks request, which answers `bearerToken()`, and a plain
|
|
22
|
+
* `Request`, which only has headers. Written out rather than left as `any` so
|
|
23
|
+
* the optional chaining below is checked against something - as `any` it was
|
|
24
|
+
* indistinguishable from probing for members that do not exist on either.
|
|
25
|
+
*/
|
|
26
|
+
export declare interface TokenBearingRequest {
|
|
27
|
+
bearerToken?: () => string | undefined | null
|
|
28
|
+
headers?: Headers
|
|
29
|
+
}
|
package/dist/request-token.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{authCookieToken}from"./cookie";export function requestToken(request){let token=request?.bearerToken?.();if(!token){const header=request?.headers?.get?.("authorization")||request?.headers?.get?.("Authorization");if(typeof header==="string"&&header.startsWith("Bearer "))token=header.substring(7)}if(!token&&request?.headers)token=authCookieToken(request);return token||null}
|
|
1
|
+
import{authCookieToken}from"./cookie";export function requestToken(request){let token=request?.bearerToken?.();if(!token){const header=request?.headers?.get?.("authorization")||request?.headers?.get?.("Authorization");if(typeof header==="string"&&header.startsWith("Bearer "))token=header.substring(7)}if(!token&&request?.headers)token=authCookieToken({headers:request.headers});return token||null}
|
package/dist/tokens.d.ts
CHANGED
|
@@ -1,19 +1,4 @@
|
|
|
1
1
|
import type { AccessToken, CreateClientOptions, CreateClientResult, DatabaseDriver, OAuthClient, PersonalAccessTokenResult, RefreshTokenResult, TokenScopes } from '@stacksjs/types';
|
|
2
|
-
/**
|
|
3
|
-
* Read `users.password_changed_at` for a user.
|
|
4
|
-
*
|
|
5
|
-
* Binds a token's validity to the account's credential state: a token
|
|
6
|
-
* issued before the user last changed their password is no longer
|
|
7
|
-
* trusted, regardless of its own `revoked`/`expires_at` flags. This is
|
|
8
|
-
* the durable, use-time backstop behind the post-reset revocation sweep
|
|
9
|
-
* (#1947) — even a freshly minted pair that the sweep never saw is
|
|
10
|
-
* rejected on first use.
|
|
11
|
-
*
|
|
12
|
-
* Returns `null` on ANY error (missing column / missing table) so a
|
|
13
|
-
* not-yet-migrated database degrades to legacy-allow rather than locking
|
|
14
|
-
* everyone out. Accepts an optional query runner so the refresh exchange
|
|
15
|
-
* can read the stamp inside its own transaction.
|
|
16
|
-
*/
|
|
17
2
|
export declare function getPasswordChangedAt(userId: unknown, q?: { unsafe: (sql: string, params?: any[]) => any }): Promise<Date | null>;
|
|
18
3
|
/**
|
|
19
4
|
* True when a credential issued at `createdAt` predates the user's last
|
package/dist/tokens.js
CHANGED
|
@@ -23,7 +23,7 @@ import{createHash,randomBytes}from"node:crypto";import{db}from"@stacksjs/databas
|
|
|
23
23
|
VALUES (?, ?, ?, ?, ?, 0, ?, ?, ?, ${appNow()}, ${appNow()})
|
|
24
24
|
`,[userId,client.id,hashedToken,name,JSON.stringify(scopes),sqlDateTime(expiresAt),agent,address]);const row=(await db.unsafe(`
|
|
25
25
|
SELECT * FROM oauth_access_tokens WHERE token = ${param(1)} LIMIT 1
|
|
26
|
-
`,[hashedToken]))[0];if(!row)throw new HttpError(500,"Failed to create access token - inserted row not found");const accessToken={id:row.id,userId:row.user_id,clientId:row.oauth_client_id,name:row.name,scopes:parseScopes(row.scopes),revoked:!1,expiresAt,createdAt:new Date(row.created_at),updatedAt:new Date(row.updated_at)};let refreshTokenPlain;if(withRefreshToken){refreshTokenPlain=generateSecureToken(40);const hashedRefreshToken=hashToken(refreshTokenPlain),refreshExpiresAt=new Date;refreshExpiresAt.setDate(refreshExpiresAt.getDate()+refreshExpiresInDays);if(isPostgres)await db.unsafe(`
|
|
26
|
+
`,[hashedToken]))[0];if(!row)throw new HttpError(500,"Failed to create access token - inserted row not found");const accessToken={id:row.id,userId:row.user_id,clientId:row.oauth_client_id,name:row.name,scopes:parseScopes(row.scopes),revoked:!1,expiresAt,createdAt:new Date(row.created_at),updatedAt:row.updated_at?new Date(row.updated_at):new Date(row.created_at)};let refreshTokenPlain;if(withRefreshToken){refreshTokenPlain=generateSecureToken(40);const hashedRefreshToken=hashToken(refreshTokenPlain),refreshExpiresAt=new Date;refreshExpiresAt.setDate(refreshExpiresAt.getDate()+refreshExpiresInDays);if(isPostgres)await db.unsafe(`
|
|
27
27
|
INSERT INTO oauth_refresh_tokens (access_token_id, token, revoked, expires_at, created_at)
|
|
28
28
|
VALUES ($1, $2, false, $3, ${appNow()})
|
|
29
29
|
`,[accessToken.id,hashedRefreshToken,sqlDateTime(refreshExpiresAt)]);else await db.unsafe(`
|
|
@@ -53,7 +53,7 @@ import{createHash,randomBytes}from"node:crypto";import{db}from"@stacksjs/databas
|
|
|
53
53
|
VALUES (?, ?, ?, ?, ?, 0, ?, ${appNow()}, ${appNow()})
|
|
54
54
|
`,[refreshRow.user_id,refreshRow.oauth_client_id,hashedToken,refreshRow.name,refreshRow.scopes,sqlDateTime(expiresAt)]);const row=(await trx.unsafe(`
|
|
55
55
|
SELECT * FROM oauth_access_tokens WHERE token = ${param(1)} LIMIT 1
|
|
56
|
-
`,[hashedToken]))[0],accessToken={id:row.id,userId:row.user_id,clientId:row.oauth_client_id,name:row.name,scopes:parseScopes(row.scopes),revoked:!1,expiresAt,createdAt:new Date(row.created_at),updatedAt:new Date(row.updated_at)};if(isIssuedBeforePasswordChange(row.created_at,await getPasswordChangedAt(refreshRow.user_id,trx)))throw new HttpError(401,"Invalid or expired refresh token");const newRefreshTokenPlain=generateSecureToken(40),newHashedRefreshToken=hashToken(newRefreshTokenPlain),refreshExpiresAt=new Date;refreshExpiresAt.setDate(refreshExpiresAt.getDate()+refreshExpiresInDays);if(isPostgres)await trx.unsafe(`
|
|
56
|
+
`,[hashedToken]))[0];if(!row)throw new HttpError(500,"Failed to read back the access token that was just created.");const accessToken={id:row.id,userId:row.user_id,clientId:row.oauth_client_id,name:row.name||"access-token",scopes:parseScopes(row.scopes),revoked:!1,expiresAt,createdAt:new Date(row.created_at),updatedAt:row.updated_at?new Date(row.updated_at):new Date(row.created_at)};if(isIssuedBeforePasswordChange(row.created_at,await getPasswordChangedAt(refreshRow.user_id,trx)))throw new HttpError(401,"Invalid or expired refresh token");const newRefreshTokenPlain=generateSecureToken(40),newHashedRefreshToken=hashToken(newRefreshTokenPlain),refreshExpiresAt=new Date;refreshExpiresAt.setDate(refreshExpiresAt.getDate()+refreshExpiresInDays);if(isPostgres)await trx.unsafe(`
|
|
57
57
|
INSERT INTO oauth_refresh_tokens (access_token_id, token, revoked, expires_at, created_at)
|
|
58
58
|
VALUES ($1, $2, false, $3, ${appNow()})
|
|
59
59
|
`,[accessToken.id,newHashedRefreshToken,sqlDateTime(refreshExpiresAt)]);else await trx.unsafe(`
|
|
@@ -75,13 +75,13 @@ import{createHash,randomBytes}from"node:crypto";import{db}from"@stacksjs/databas
|
|
|
75
75
|
WHERE access_token_id IN (
|
|
76
76
|
SELECT id FROM oauth_access_tokens WHERE user_id = ${param(1)}
|
|
77
77
|
)
|
|
78
|
-
`,[userId])}export async function deleteExpiredRefreshTokens(){const
|
|
78
|
+
`,[userId])}export async function deleteExpiredRefreshTokens(){const written=await db.unsafe(`
|
|
79
79
|
DELETE FROM oauth_refresh_tokens
|
|
80
80
|
WHERE expires_at < ${appNow()}
|
|
81
|
-
`);return
|
|
81
|
+
`);return Number(written?.changes??written?.rowCount??0)}export async function deleteRevokedRefreshTokens(daysOld=7){const cutoffDate=new Date;cutoffDate.setDate(cutoffDate.getDate()-daysOld);const written=await db.unsafe(`
|
|
82
82
|
DELETE FROM oauth_refresh_tokens
|
|
83
83
|
WHERE revoked = ${boolTrue} AND created_at < ${param(1)}
|
|
84
|
-
`,[sqlDateTime(cutoffDate)]);return
|
|
84
|
+
`,[sqlDateTime(cutoffDate)]);return Number(written?.changes??written?.rowCount??0)}export async function revokeToken(plainTextToken){const hashedToken=bearerLookupHash(plainTextToken);await db.unsafe(`
|
|
85
85
|
UPDATE oauth_refresh_tokens
|
|
86
86
|
SET revoked = ${boolTrue}
|
|
87
87
|
WHERE access_token_id IN (
|
|
@@ -128,18 +128,18 @@ import{createHash,randomBytes}from"node:crypto";import{db}from"@stacksjs/databas
|
|
|
128
128
|
WHERE access_token_id IN (
|
|
129
129
|
SELECT id FROM oauth_access_tokens WHERE expires_at < ${appNow()}
|
|
130
130
|
)
|
|
131
|
-
`);const
|
|
131
|
+
`);const written=await db.unsafe(`
|
|
132
132
|
DELETE FROM oauth_access_tokens
|
|
133
133
|
WHERE expires_at < ${appNow()}
|
|
134
|
-
`);return
|
|
134
|
+
`);return Number(written?.changes??written?.rowCount??0)}export async function deleteRevokedTokens(daysOld=7){const cutoffDate=new Date;cutoffDate.setDate(cutoffDate.getDate()-daysOld);await db.unsafe(`
|
|
135
135
|
DELETE FROM oauth_refresh_tokens
|
|
136
136
|
WHERE access_token_id IN (
|
|
137
137
|
SELECT id FROM oauth_access_tokens WHERE revoked = ${boolTrue} AND updated_at < ${param(1)}
|
|
138
138
|
)
|
|
139
|
-
`,[sqlDateTime(cutoffDate)]);const
|
|
139
|
+
`,[sqlDateTime(cutoffDate)]);const written=await db.unsafe(`
|
|
140
140
|
DELETE FROM oauth_access_tokens
|
|
141
141
|
WHERE revoked = ${boolTrue} AND updated_at < ${param(1)}
|
|
142
|
-
`,[sqlDateTime(cutoffDate)]);return
|
|
142
|
+
`,[sqlDateTime(cutoffDate)]);return Number(written?.changes??written?.rowCount??0)}export async function clients(userId){return(await db.unsafe(`
|
|
143
143
|
SELECT * FROM oauth_clients
|
|
144
144
|
WHERE user_id = ${param(1)} AND revoked = ${boolFalse}
|
|
145
145
|
ORDER BY created_at DESC
|
|
@@ -151,9 +151,9 @@ import{createHash,randomBytes}from"node:crypto";import{db}from"@stacksjs/databas
|
|
|
151
151
|
`,[options.name,secret,options.redirect,options.personalAccessClient||!1,options.passwordClient||!1]);else await db.unsafe(`
|
|
152
152
|
INSERT INTO oauth_clients (name, secret, provider, redirect, personal_access_client, password_client, revoked, created_at)
|
|
153
153
|
VALUES (?, ?, 'local', ?, ?, ?, 0, ${appNow()})
|
|
154
|
-
`,[options.name,secret,options.redirect,options.personalAccessClient?1:0,options.passwordClient?1:0]);const
|
|
154
|
+
`,[options.name,secret,options.redirect,options.personalAccessClient?1:0,options.passwordClient?1:0]);const createdClient=(await db.unsafe(`
|
|
155
155
|
SELECT * FROM oauth_clients WHERE secret = ${param(1)} LIMIT 1
|
|
156
|
-
`,[secret]);return{client:mapToOAuthClient(
|
|
156
|
+
`,[secret]))[0];if(!createdClient)throw new HttpError(500,"Failed to read back the OAuth client that was just created.");return{client:mapToOAuthClient(createdClient),plainTextSecret:secret}}export async function revokeClient(clientId){await db.unsafe(`
|
|
157
157
|
UPDATE oauth_clients
|
|
158
158
|
SET revoked = ${boolTrue}, updated_at = ${appNow()}
|
|
159
159
|
WHERE id = ${param(1)}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/auth",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.73.1",
|
|
6
6
|
"description": "A more simplistic way to authenticate.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"better-dx": "^0.2.24",
|
|
65
|
-
"@stacksjs/error-handling": "0.
|
|
66
|
-
"@stacksjs/router": "0.
|
|
65
|
+
"@stacksjs/error-handling": "0.73.1",
|
|
66
|
+
"@stacksjs/router": "0.73.1"
|
|
67
67
|
}
|
|
68
68
|
}
|