@stacksjs/auth 0.75.66 → 0.75.67

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.
@@ -1,4 +1,15 @@
1
1
  import { User } from '@stacksjs/orm';
2
+ /**
3
+ * Read the active request's IP + User-Agent for session fingerprinting.
4
+ * Returns nulls when called outside a request scope.
5
+ *
6
+ * The previous implementation hardcoded both fields to `null`,
7
+ * defeating hijack detection (a stolen sessionId from a coffee-shop
8
+ * laptop is indistinguishable from the legitimate owner without
9
+ * IP/UA fingerprints to compare against). See
10
+ * stacksjs/stacks#1860 H-6.
11
+ */
12
+ export declare function readRequestFingerprint(override?: { ip?: string | null, userAgent?: string | null }): { ip: string | null, userAgent: string | null };
2
13
  /**
3
14
  * Decide whether a stored session must be rejected because its captured
4
15
  * fingerprint no longer matches the current request (basic hijack detection,
@@ -1 +1 @@
1
- import{HttpError}from"@stacksjs/error-handling";import{log}from"@stacksjs/logging";import{User}from"@stacksjs/orm";import{verifyHash}from"@stacksjs/security";import{config}from"@stacksjs/config";import{db,getDatabaseDialect,parseSqlDateTime,sqlDateTime}from"@stacksjs/database/runtime";import{getCurrentRequest}from"@stacksjs/router";import{DUMMY_BCRYPT_HASH}from"./internal-constants";import{findAuthUserByEmail,normalizeAuthEmail}from"./credential-user";import{RateLimiter}from"./rate-limiter";import{withVerifiedPassword}from"./credential-version";import{schedulePasswordRehash}from"./password-rehash";function generateSessionId(){const bytes=crypto.getRandomValues(new Uint8Array(32));return Array.from(bytes,(b)=>b.toString(16).padStart(2,"0")).join("")}function readRequestFingerprint(override){if(override)return{ip:override.ip??null,userAgent:override.userAgent??null};const req=getCurrentRequest();if(!req)return{ip:null,userAgent:null};const headers=req.headers,fwd=headers?.get?.("x-forwarded-for")||headers?.get?.("X-Forwarded-For")||"",realIp=headers?.get?.("x-real-ip")||headers?.get?.("X-Real-IP")||"",ip=(fwd?fwd.split(",")[0].trim():"")||realIp||null,userAgent=headers?.get?.("user-agent")||headers?.get?.("User-Agent")||null;return{ip,userAgent}}export function fingerprintMismatch(enforce,stored,current){if(!enforce)return!1;const enforceIp=enforce===!0||!!enforce.ip,enforceUa=enforce===!0||!!enforce.userAgent;if(!enforceIp&&!enforceUa)return!1;if(enforceIp&&current.ip!=null&&stored.ip!=null&&String(stored.ip)!==current.ip)return!0;if(enforceUa&&current.userAgent!=null&&stored.userAgent!=null&&String(stored.userAgent)!==current.userAgent)return!0;return!1}function sessionFingerprintRejected(session){return fingerprintMismatch(config.auth?.session?.enforceFingerprint,{ip:session.ip_address,userAgent:session.user_agent},readRequestFingerprint())}export async function sessionLogin(email,password,fingerprint){const normalizedEmail=normalizeAuthEmail(email||""),isRateLimited=await RateLimiter.isRateLimited(normalizedEmail),user=await findAuthUserByEmail(normalizedEmail),hashToVerify=user?.password||DUMMY_BCRYPT_HASH,isValid=await verifyHash(password,hashToVerify);if(isRateLimited)throw new HttpError(429,"Too many login attempts. Please try again later.");if(!isValid||!user){await RateLimiter.recordFailedAttempt(normalizedEmail);throw new HttpError(401,"Invalid credentials")}await RateLimiter.resetAttempts(normalizedEmail);const sessionId=generateSessionId(),expiresAt=new Date(Date.now()+86400000);if(getDatabaseDialect()==="mysql")expiresAt.setUTCMilliseconds(0);const{ip,userAgent}=readRequestFingerprint(fingerprint);let persisted;try{persisted=await withVerifiedPassword(user.id,hashToVerify,async()=>{await db.insertInto("sessions").values({id:sessionId,user_id:user.id,ip_address:ip,user_agent:userAgent,payload:"{}",last_activity:Math.floor(Date.now()/1000),expires_at:sqlDateTime(expiresAt)}).execute();const stored=await db.primary.selectFrom("sessions").where("id","=",sessionId).select(["user_id","expires_at"]).executeTakeFirst();if(!stored||String(stored.user_id)!==String(user.id)||parseSqlDateTime(stored.expires_at)?.getTime()!==expiresAt.getTime()||(parseSqlDateTime(stored.expires_at)?.getTime()??0)<=Date.now())throw Error("Session insert did not persist a usable credential for the verified user.");return!0})}catch(err){log.error(`[auth] Session persistence failed for user#${user.id}: ${err.message}`);throw new HttpError(500,"Session could not be created. Ensure the `sessions` table exists (run `./buddy migrate`).")}if(!persisted)throw new HttpError(401,"Invalid credentials");schedulePasswordRehash(user.id,password,hashToVerify);log.debug(`[auth] Session created for user#${user.id}`);return{user,sessionId}}export async function sessionLogout(sessionId){await db.transaction(async()=>{await db.deleteFrom("sessions").where("id","=",sessionId).execute();if(await db.primary.selectFrom("sessions").where("id","=",sessionId).select("id").executeTakeFirst())throw new HttpError(500,"Session could not be destroyed.")});log.debug("[auth] Session destroyed")}export async function sessionDestroyAll(userId){try{await db.transaction(async()=>{await db.deleteFrom("sessions").where("user_id","=",userId).execute();if(await db.primary.selectFrom("sessions").where("user_id","=",userId).select("id").executeTakeFirst())throw new HttpError(500,"Sessions could not be destroyed.")})}catch(err){const message=err&&typeof err==="object"&&"message"in err?String(err.message):String(err);if(/^(?:no such table: (?:main\.)?sessions|relation "sessions" does not exist|Table '(?:[^'.]+\.)?sessions' doesn't exist)$/i.test(message))return;throw err}}async function deleteObservedExpiredSession(sessionId,expiresAt){const cleanup=db.deleteFrom("sessions").where("id","=",sessionId);await(expiresAt==null?cleanup.whereNull("expires_at"):cleanup.where("expires_at","=",expiresAt)).execute()}async function deleteObservedOrphanedSession(sessionId,userId,expiresAt){let cleanup=db.deleteFrom("sessions").where("id","=",sessionId).where("user_id","=",userId);cleanup=expiresAt==null?cleanup.whereNull("expires_at"):cleanup.where("expires_at","=",expiresAt);await cleanup.execute()}async function sessionOwnerExists(userId,lock=!1){let query=db.primary.selectFrom("users").where("id","=",userId).select("id");if(lock&&getDatabaseDialect()!=="sqlite")query=query.lockForUpdate();return await query.executeTakeFirst()!==void 0}function sessionIdleTimeoutExceeded(lastActivity){const idleMs=config.auth?.idleTimeout??0;if(idleMs<=0)return!1;const seconds=Number(lastActivity);if(!Number.isFinite(seconds)||seconds<=0)return!0;return Date.now()-seconds*1000>idleMs}async function deleteObservedIdleSession(sessionId,userId,expiresAt,lastActivity){let cleanup=db.deleteFrom("sessions").where("id","=",sessionId).where("user_id","=",userId);cleanup=expiresAt==null?cleanup.whereNull("expires_at"):cleanup.where("expires_at","=",expiresAt);cleanup=lastActivity==null?cleanup.whereNull("last_activity"):cleanup.where("last_activity","=",lastActivity);await cleanup.execute()}async function touchSessionActivity(sessionId,expiresAt,lastActivity){if((config.auth?.idleTimeout??0)<=0)return;let touch=db.updateTable("sessions").set({last_activity:Math.floor(Date.now()/1000)}).where("id","=",sessionId);touch=expiresAt==null?touch.whereNull("expires_at"):touch.where("expires_at","=",expiresAt);touch=lastActivity==null?touch.whereNull("last_activity"):touch.where("last_activity","=",lastActivity);await touch.execute()}export async function sessionUser(sessionId){try{const query=db.primary.selectFrom("sessions").where("id","=",sessionId),session=config.auth?.session?.enforceFingerprint?await query.select(["user_id","expires_at","last_activity","ip_address","user_agent"]).executeTakeFirst():await query.select(["user_id","expires_at","last_activity"]).executeTakeFirst();if(!session)return;const expiresAt=parseSqlDateTime(session.expires_at)?.getTime()??0;if(Date.now()>=expiresAt){await deleteObservedExpiredSession(sessionId,session.expires_at);return}if(sessionIdleTimeoutExceeded(session.last_activity)){await deleteObservedIdleSession(sessionId,session.user_id,session.expires_at,session.last_activity);return}if(sessionFingerprintRejected(session)){log.warn("[auth] Session fingerprint mismatch - rejecting request (possible hijack, session left intact)");return}const userId=session.user_id;if(!await sessionOwnerExists(userId)){await deleteObservedOrphanedSession(sessionId,userId,session.expires_at);return}await touchSessionActivity(sessionId,session.expires_at,session.last_activity);return await User.find(userId)}catch{return}}export async function sessionCheck(sessionId){try{const query=db.primary.selectFrom("sessions").where("id","=",sessionId),session=config.auth?.session?.enforceFingerprint?await query.select(["user_id","expires_at","last_activity","ip_address","user_agent"]).executeTakeFirst():await query.select(["user_id","expires_at","last_activity"]).executeTakeFirst();if(!session)return!1;const expiresAt=parseSqlDateTime(session.expires_at)?.getTime()??0;if(Date.now()>=expiresAt){await deleteObservedExpiredSession(sessionId,session.expires_at);return!1}if(sessionIdleTimeoutExceeded(session.last_activity)){await deleteObservedIdleSession(sessionId,session.user_id,session.expires_at,session.last_activity);return!1}if(sessionFingerprintRejected(session))return!1;const userId=session.user_id;if(!await sessionOwnerExists(userId)){await deleteObservedOrphanedSession(sessionId,userId,session.expires_at);return!1}await touchSessionActivity(sessionId,session.expires_at,session.last_activity);return!0}catch{return!1}}export async function sessionRefresh(sessionId,ttlMs=86400000){if(!Number.isFinite(ttlMs)||ttlMs<=0)return!1;try{const query=db.primary.selectFrom("sessions").where("id","=",sessionId),session=config.auth?.session?.enforceFingerprint?await query.select(["user_id","expires_at","last_activity","ip_address","user_agent"]).executeTakeFirst():await query.select(["user_id","expires_at","last_activity"]).executeTakeFirst();if(!session)return!1;const expiresAt=parseSqlDateTime(session.expires_at)?.getTime()??0;if(Date.now()>=expiresAt){await deleteObservedExpiredSession(sessionId,session.expires_at);return!1}if(sessionIdleTimeoutExceeded(session.last_activity)){await deleteObservedIdleSession(sessionId,session.user_id,session.expires_at,session.last_activity);return!1}if(sessionFingerprintRejected(session))return!1;return await db.transaction(async()=>{const mysql=getDatabaseDialect()==="mysql";if(mysql){if(!await db.primary.selectFrom("sessions").where("id","=",sessionId).where("expires_at","=",session.expires_at).select("id").lockForUpdate().executeTakeFirst())return!1}const userId=session.user_id;if(!await sessionOwnerExists(userId,!0)){await deleteObservedOrphanedSession(sessionId,userId,session.expires_at);return!1}const newExpiry=new Date(Date.now()+ttlMs);if(mysql)newExpiry.setUTCMilliseconds(0);if(!Number.isFinite(newExpiry.getTime())||newExpiry.getTime()<=Date.now())return!1;const lastActivity=Math.floor(Date.now()/1000),result=await db.updateTable("sessions").set({expires_at:sqlDateTime(newExpiry),last_activity:lastActivity}).where("id","=",sessionId).where("expires_at","=",session.expires_at).where("user_id","=",session.user_id).returning("id").executeTakeFirst();if(Date.now()>=expiresAt||Date.now()>=newExpiry.getTime())throw Error("[auth] Session expired during renewal.");if(!result)return!1;let storedQuery=db.primary.selectFrom("sessions").where("id","=",sessionId).select(["user_id","expires_at","last_activity"]);if(mysql)storedQuery=storedQuery.lockForUpdate();const stored=await storedQuery.executeTakeFirst();if(!stored||String(stored.user_id)!==String(session.user_id)||parseSqlDateTime(stored.expires_at)?.getTime()!==newExpiry.getTime()||Number(stored.last_activity)!==lastActivity||Date.now()>=Math.min(expiresAt,newExpiry.getTime()))throw Error("[auth] Session renewal did not persist the requested credential.");if(!await sessionOwnerExists(userId,!0))throw Error("[auth] Session owner disappeared during renewal.");return!0})}catch{return!1}}export const SessionAuth={login:sessionLogin,logout:sessionLogout,destroyAll:sessionDestroyAll,user:sessionUser,check:sessionCheck,refresh:sessionRefresh};
1
+ import{HttpError}from"@stacksjs/error-handling";import{log}from"@stacksjs/logging";import{User}from"@stacksjs/orm";import{verifyHash}from"@stacksjs/security";import{config}from"@stacksjs/config";import{db,getDatabaseDialect,parseSqlDateTime,sqlDateTime}from"@stacksjs/database/runtime";import{clientAddress,getCurrentRequest}from"@stacksjs/router";import{DUMMY_BCRYPT_HASH}from"./internal-constants";import{findAuthUserByEmail,normalizeAuthEmail}from"./credential-user";import{RateLimiter}from"./rate-limiter";import{withVerifiedPassword}from"./credential-version";import{schedulePasswordRehash}from"./password-rehash";function generateSessionId(){const bytes=crypto.getRandomValues(new Uint8Array(32));return Array.from(bytes,(b)=>b.toString(16).padStart(2,"0")).join("")}export function readRequestFingerprint(override){if(override)return{ip:override.ip??null,userAgent:override.userAgent??null};const req=getCurrentRequest();if(!req)return{ip:null,userAgent:null};const headers=req.headers,ip=clientAddress(req),userAgent=headers?.get?.("user-agent")||headers?.get?.("User-Agent")||null;return{ip,userAgent}}export function fingerprintMismatch(enforce,stored,current){if(!enforce)return!1;const enforceIp=enforce===!0||!!enforce.ip,enforceUa=enforce===!0||!!enforce.userAgent;if(!enforceIp&&!enforceUa)return!1;if(enforceIp&&current.ip!=null&&stored.ip!=null&&String(stored.ip)!==current.ip)return!0;if(enforceUa&&current.userAgent!=null&&stored.userAgent!=null&&String(stored.userAgent)!==current.userAgent)return!0;return!1}function sessionFingerprintRejected(session){return fingerprintMismatch(config.auth?.session?.enforceFingerprint,{ip:session.ip_address,userAgent:session.user_agent},readRequestFingerprint())}export async function sessionLogin(email,password,fingerprint){const normalizedEmail=normalizeAuthEmail(email||""),isRateLimited=await RateLimiter.isRateLimited(normalizedEmail),user=await findAuthUserByEmail(normalizedEmail),hashToVerify=user?.password||DUMMY_BCRYPT_HASH,isValid=await verifyHash(password,hashToVerify);if(isRateLimited)throw new HttpError(429,"Too many login attempts. Please try again later.");if(!isValid||!user){await RateLimiter.recordFailedAttempt(normalizedEmail);throw new HttpError(401,"Invalid credentials")}await RateLimiter.resetAttempts(normalizedEmail);const sessionId=generateSessionId(),expiresAt=new Date(Date.now()+86400000);if(getDatabaseDialect()==="mysql")expiresAt.setUTCMilliseconds(0);const{ip,userAgent}=readRequestFingerprint(fingerprint);let persisted;try{persisted=await withVerifiedPassword(user.id,hashToVerify,async()=>{await db.insertInto("sessions").values({id:sessionId,user_id:user.id,ip_address:ip,user_agent:userAgent,payload:"{}",last_activity:Math.floor(Date.now()/1000),expires_at:sqlDateTime(expiresAt)}).execute();const stored=await db.primary.selectFrom("sessions").where("id","=",sessionId).select(["user_id","expires_at"]).executeTakeFirst();if(!stored||String(stored.user_id)!==String(user.id)||parseSqlDateTime(stored.expires_at)?.getTime()!==expiresAt.getTime()||(parseSqlDateTime(stored.expires_at)?.getTime()??0)<=Date.now())throw Error("Session insert did not persist a usable credential for the verified user.");return!0})}catch(err){log.error(`[auth] Session persistence failed for user#${user.id}: ${err.message}`);throw new HttpError(500,"Session could not be created. Ensure the `sessions` table exists (run `./buddy migrate`).")}if(!persisted)throw new HttpError(401,"Invalid credentials");schedulePasswordRehash(user.id,password,hashToVerify);log.debug(`[auth] Session created for user#${user.id}`);return{user,sessionId}}export async function sessionLogout(sessionId){await db.transaction(async()=>{await db.deleteFrom("sessions").where("id","=",sessionId).execute();if(await db.primary.selectFrom("sessions").where("id","=",sessionId).select("id").executeTakeFirst())throw new HttpError(500,"Session could not be destroyed.")});log.debug("[auth] Session destroyed")}export async function sessionDestroyAll(userId){try{await db.transaction(async()=>{await db.deleteFrom("sessions").where("user_id","=",userId).execute();if(await db.primary.selectFrom("sessions").where("user_id","=",userId).select("id").executeTakeFirst())throw new HttpError(500,"Sessions could not be destroyed.")})}catch(err){const message=err&&typeof err==="object"&&"message"in err?String(err.message):String(err);if(/^(?:no such table: (?:main\.)?sessions|relation "sessions" does not exist|Table '(?:[^'.]+\.)?sessions' doesn't exist)$/i.test(message))return;throw err}}async function deleteObservedExpiredSession(sessionId,expiresAt){const cleanup=db.deleteFrom("sessions").where("id","=",sessionId);await(expiresAt==null?cleanup.whereNull("expires_at"):cleanup.where("expires_at","=",expiresAt)).execute()}async function deleteObservedOrphanedSession(sessionId,userId,expiresAt){let cleanup=db.deleteFrom("sessions").where("id","=",sessionId).where("user_id","=",userId);cleanup=expiresAt==null?cleanup.whereNull("expires_at"):cleanup.where("expires_at","=",expiresAt);await cleanup.execute()}async function sessionOwnerExists(userId,lock=!1){let query=db.primary.selectFrom("users").where("id","=",userId).select("id");if(lock&&getDatabaseDialect()!=="sqlite")query=query.lockForUpdate();return await query.executeTakeFirst()!==void 0}function sessionIdleTimeoutExceeded(lastActivity){const idleMs=config.auth?.idleTimeout??0;if(idleMs<=0)return!1;const seconds=Number(lastActivity);if(!Number.isFinite(seconds)||seconds<=0)return!0;return Date.now()-seconds*1000>idleMs}async function deleteObservedIdleSession(sessionId,userId,expiresAt,lastActivity){let cleanup=db.deleteFrom("sessions").where("id","=",sessionId).where("user_id","=",userId);cleanup=expiresAt==null?cleanup.whereNull("expires_at"):cleanup.where("expires_at","=",expiresAt);cleanup=lastActivity==null?cleanup.whereNull("last_activity"):cleanup.where("last_activity","=",lastActivity);await cleanup.execute()}async function touchSessionActivity(sessionId,expiresAt,lastActivity){if((config.auth?.idleTimeout??0)<=0)return;let touch=db.updateTable("sessions").set({last_activity:Math.floor(Date.now()/1000)}).where("id","=",sessionId);touch=expiresAt==null?touch.whereNull("expires_at"):touch.where("expires_at","=",expiresAt);touch=lastActivity==null?touch.whereNull("last_activity"):touch.where("last_activity","=",lastActivity);await touch.execute()}export async function sessionUser(sessionId){try{const query=db.primary.selectFrom("sessions").where("id","=",sessionId),session=config.auth?.session?.enforceFingerprint?await query.select(["user_id","expires_at","last_activity","ip_address","user_agent"]).executeTakeFirst():await query.select(["user_id","expires_at","last_activity"]).executeTakeFirst();if(!session)return;const expiresAt=parseSqlDateTime(session.expires_at)?.getTime()??0;if(Date.now()>=expiresAt){await deleteObservedExpiredSession(sessionId,session.expires_at);return}if(sessionIdleTimeoutExceeded(session.last_activity)){await deleteObservedIdleSession(sessionId,session.user_id,session.expires_at,session.last_activity);return}if(sessionFingerprintRejected(session)){log.warn("[auth] Session fingerprint mismatch - rejecting request (possible hijack, session left intact)");return}const userId=session.user_id;if(!await sessionOwnerExists(userId)){await deleteObservedOrphanedSession(sessionId,userId,session.expires_at);return}await touchSessionActivity(sessionId,session.expires_at,session.last_activity);return await User.find(userId)}catch{return}}export async function sessionCheck(sessionId){try{const query=db.primary.selectFrom("sessions").where("id","=",sessionId),session=config.auth?.session?.enforceFingerprint?await query.select(["user_id","expires_at","last_activity","ip_address","user_agent"]).executeTakeFirst():await query.select(["user_id","expires_at","last_activity"]).executeTakeFirst();if(!session)return!1;const expiresAt=parseSqlDateTime(session.expires_at)?.getTime()??0;if(Date.now()>=expiresAt){await deleteObservedExpiredSession(sessionId,session.expires_at);return!1}if(sessionIdleTimeoutExceeded(session.last_activity)){await deleteObservedIdleSession(sessionId,session.user_id,session.expires_at,session.last_activity);return!1}if(sessionFingerprintRejected(session))return!1;const userId=session.user_id;if(!await sessionOwnerExists(userId)){await deleteObservedOrphanedSession(sessionId,userId,session.expires_at);return!1}await touchSessionActivity(sessionId,session.expires_at,session.last_activity);return!0}catch{return!1}}export async function sessionRefresh(sessionId,ttlMs=86400000){if(!Number.isFinite(ttlMs)||ttlMs<=0)return!1;try{const query=db.primary.selectFrom("sessions").where("id","=",sessionId),session=config.auth?.session?.enforceFingerprint?await query.select(["user_id","expires_at","last_activity","ip_address","user_agent"]).executeTakeFirst():await query.select(["user_id","expires_at","last_activity"]).executeTakeFirst();if(!session)return!1;const expiresAt=parseSqlDateTime(session.expires_at)?.getTime()??0;if(Date.now()>=expiresAt){await deleteObservedExpiredSession(sessionId,session.expires_at);return!1}if(sessionIdleTimeoutExceeded(session.last_activity)){await deleteObservedIdleSession(sessionId,session.user_id,session.expires_at,session.last_activity);return!1}if(sessionFingerprintRejected(session))return!1;return await db.transaction(async()=>{const mysql=getDatabaseDialect()==="mysql";if(mysql){if(!await db.primary.selectFrom("sessions").where("id","=",sessionId).where("expires_at","=",session.expires_at).select("id").lockForUpdate().executeTakeFirst())return!1}const userId=session.user_id;if(!await sessionOwnerExists(userId,!0)){await deleteObservedOrphanedSession(sessionId,userId,session.expires_at);return!1}const newExpiry=new Date(Date.now()+ttlMs);if(mysql)newExpiry.setUTCMilliseconds(0);if(!Number.isFinite(newExpiry.getTime())||newExpiry.getTime()<=Date.now())return!1;const lastActivity=Math.floor(Date.now()/1000),result=await db.updateTable("sessions").set({expires_at:sqlDateTime(newExpiry),last_activity:lastActivity}).where("id","=",sessionId).where("expires_at","=",session.expires_at).where("user_id","=",session.user_id).returning("id").executeTakeFirst();if(Date.now()>=expiresAt||Date.now()>=newExpiry.getTime())throw Error("[auth] Session expired during renewal.");if(!result)return!1;let storedQuery=db.primary.selectFrom("sessions").where("id","=",sessionId).select(["user_id","expires_at","last_activity"]);if(mysql)storedQuery=storedQuery.lockForUpdate();const stored=await storedQuery.executeTakeFirst();if(!stored||String(stored.user_id)!==String(session.user_id)||parseSqlDateTime(stored.expires_at)?.getTime()!==newExpiry.getTime()||Number(stored.last_activity)!==lastActivity||Date.now()>=Math.min(expiresAt,newExpiry.getTime()))throw Error("[auth] Session renewal did not persist the requested credential.");if(!await sessionOwnerExists(userId,!0))throw Error("[auth] Session owner disappeared during renewal.");return!0})}catch{return!1}}export const SessionAuth={login:sessionLogin,logout:sessionLogout,destroyAll:sessionDestroyAll,user:sessionUser,check:sessionCheck,refresh:sessionRefresh};
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/auth",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.66",
5
+ "version": "0.75.67",
6
6
  "description": "A more simplistic way to authenticate.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -57,19 +57,19 @@
57
57
  "prepublishOnly": "bun run build"
58
58
  },
59
59
  "dependencies": {
60
- "@stacksjs/bun-router": "^0.1.18",
61
- "@stacksjs/cache": "0.75.66",
62
- "@stacksjs/config": "0.75.66",
63
- "@stacksjs/database": "0.75.66",
64
- "@stacksjs/email": "0.75.66",
65
- "@stacksjs/env": "0.75.66",
66
- "@stacksjs/error-handling": "0.75.66",
67
- "@stacksjs/logging": "0.75.66",
68
- "@stacksjs/orm": "0.75.66",
69
- "@stacksjs/path": "0.75.66",
70
- "@stacksjs/router": "0.75.66",
71
- "@stacksjs/security": "0.75.66",
72
- "@stacksjs/storage": "0.75.66",
60
+ "@stacksjs/bun-router": "^0.1.22",
61
+ "@stacksjs/cache": "0.75.67",
62
+ "@stacksjs/config": "0.75.67",
63
+ "@stacksjs/database": "0.75.67",
64
+ "@stacksjs/email": "0.75.67",
65
+ "@stacksjs/env": "0.75.67",
66
+ "@stacksjs/error-handling": "0.75.67",
67
+ "@stacksjs/logging": "0.75.67",
68
+ "@stacksjs/orm": "0.75.67",
69
+ "@stacksjs/path": "0.75.67",
70
+ "@stacksjs/router": "0.75.67",
71
+ "@stacksjs/security": "0.75.67",
72
+ "@stacksjs/storage": "0.75.67",
73
73
  "@stacksjs/ts-auth": "^0.4.5",
74
74
  "ts-qr-codes": "^0.1.8"
75
75
  },