New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@a-type/auth

Package Overview
Dependencies
Maintainers
1
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@a-type/auth - npm Package Compare versions

Comparing version 0.3.7 to 0.3.8

dist/esm/session.test.js

9

dist/esm/handlers.js

@@ -268,2 +268,10 @@ import { AuthError } from './error.js';

}
async function handleRefreshSessionRequest(req) {
const accessToken = sessions.getAccessToken(req);
const refreshToken = sessions.getRefreshToken(req);
if (!accessToken || !refreshToken) {
throw new AuthError('Invalid session', 401);
}
return sessions.refreshSession(accessToken, refreshToken);
}
return {

@@ -279,4 +287,5 @@ handleOAuthLoginRequest,

handleSessionRequest,
handleRefreshSessionRequest,
};
}
//# sourceMappingURL=handlers.js.map

91

dist/esm/session.js
import { parse } from 'cookie';
import { SignJWT, jwtVerify, errors } from 'jose';
import { SignJWT, jwtVerify, decodeJwt, errors, compactVerify, } from 'jose';
import { AuthError } from './error.js';
import { randomUUID } from 'crypto';
export const defaultShortNames = {

@@ -13,3 +14,3 @@ userId: 'sub',

};
this.getSession = async (req) => {
this.getAccessToken = (req) => {
var _a;

@@ -22,2 +23,11 @@ const cookieHeader = (_a = req.headers.get('cookie')) !== null && _a !== void 0 ? _a : '';

}
return cookieValue;
};
this.getRefreshToken = (req) => {
return req.headers.get(this.refreshTokenHeader);
};
this.getSession = async (req) => {
const cookieValue = this.getAccessToken(req);
if (!cookieValue)
return null;
// read the JWT from the cookie

@@ -30,6 +40,3 @@ try {

// convert the JWT claims to a session object
const session = Object.fromEntries(Object.entries(jwt.payload).map(([key, value]) => [
this.getLongName(key),
value,
]));
const session = this.readSessionFromPayload(jwt.payload);
// in dev mode, validate session has the right keys

@@ -60,3 +67,40 @@ if (this.options.mode === 'development') {

};
this.updateSession = async (session) => {
/**
* Refresh the session by re-signing the JWT with a new expiration time.
* Requires a valid refresh token.
*/
this.refreshSession = async (accessToken, refreshToken) => {
const refreshData = await jwtVerify(refreshToken, this.secret, {
issuer: this.options.issuer,
audience: this.options.audience,
});
// verify the signature of the token
await compactVerify(accessToken, this.secret);
const accessData = decodeJwt(accessToken);
if (refreshData.payload.jti !== accessData.jti) {
throw new AuthError('Invalid refresh token', 400);
}
const session = this.readSessionFromPayload(accessData);
return this.updateSession(session, { sendRefreshToken: true });
};
this.updateSession = async (session, { sendRefreshToken } = { sendRefreshToken: false }) => {
const jti = randomUUID();
const accessTokenBuilder = this.getAccessTokenBuilder(session, jti);
const jwt = await accessTokenBuilder.sign(this.secret);
const headers = {
'Set-Cookie': `${this.options.cookieName}=${jwt}; Path=/; HttpOnly; SameSite=Strict`,
};
if (sendRefreshToken) {
const refreshTokenBuilder = this.getRefreshTokenBuilder(jti);
const refreshToken = await refreshTokenBuilder.sign(this.secret);
headers[this.refreshTokenHeader] = refreshToken;
}
return headers;
};
this.clearSession = () => {
return {
'Set-Cookie': `${this.options.cookieName}=; Path=/; HttpOnly; SameSite=Strict; Max-Age=0`,
};
};
this.getAccessTokenBuilder = (session, jti) => {
var _a;

@@ -70,3 +114,4 @@ const builder = new SignJWT(Object.fromEntries(Object.entries(session).map(([key, value]) => [

.setExpirationTime((_a = this.options.expiration) !== null && _a !== void 0 ? _a : '12h')
.setSubject(session.userId);
.setSubject(session.userId)
.setJti(jti);
if (this.options.issuer) {

@@ -78,11 +123,18 @@ builder.setIssuer(this.options.issuer);

}
const jwt = await builder.sign(this.secret);
return {
'Set-Cookie': `${this.options.cookieName}=${jwt}; Path=/; HttpOnly; SameSite=Strict`,
};
return builder;
};
this.clearSession = () => {
return {
'Set-Cookie': `${this.options.cookieName}=; Path=/; HttpOnly; SameSite=Strict; Max-Age=0`,
};
this.getRefreshTokenBuilder = (jti) => {
const refreshTokenBuilder = new SignJWT({
jti,
})
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('7d');
if (this.options.issuer) {
refreshTokenBuilder.setIssuer(this.options.issuer);
}
if (this.options.audience) {
refreshTokenBuilder.setAudience(this.options.audience);
}
return refreshTokenBuilder;
};

@@ -95,2 +147,5 @@ this.getShortName = (key) => {

};
this.readSessionFromPayload = (jwt) => {
return Object.fromEntries(Object.entries(jwt).map(([key, value]) => [this.getLongName(key), value]));
};
this.secret = new TextEncoder().encode(options.secret);

@@ -104,3 +159,7 @@ this.shortNamesBackwards = Object.fromEntries(Object.entries(options.shortNames).map(([key, value]) => [value, key]));

}
get refreshTokenHeader() {
var _a;
return (_a = this.options.refreshTokenHeader) !== null && _a !== void 0 ? _a : 'x-refresh-token';
}
}
//# sourceMappingURL=session.js.map

@@ -26,2 +26,3 @@ import { AuthDB } from './db.js';

handleSessionRequest: (req: Request) => Promise<Response>;
handleRefreshSessionRequest: (req: Request) => Promise<Record<string, string>>;
};

@@ -17,2 +17,3 @@ export interface Session {

cookieName: string;
refreshTokenHeader?: string;
shortNames: ShortNames;

@@ -26,7 +27,26 @@ mode?: 'production' | 'development';

createSession: (userId: string) => Promise<Session>;
getSession: (req: Request) => Promise<Session | null>;
updateSession: (session: Session) => Promise<Record<string, string>>;
getAccessToken: (req: {
headers: Headers;
}) => string | null;
getRefreshToken: (req: {
headers: Headers;
}) => string | null;
getSession: (req: {
headers: Headers;
}) => Promise<Session | null>;
/**
* Refresh the session by re-signing the JWT with a new expiration time.
* Requires a valid refresh token.
*/
refreshSession: (accessToken: string, refreshToken: string) => Promise<Record<string, string>>;
updateSession: (session: Session, { sendRefreshToken }?: {
sendRefreshToken: boolean;
}) => Promise<Record<string, string>>;
clearSession: () => Record<string, string>;
private getAccessTokenBuilder;
private getRefreshTokenBuilder;
private getShortName;
private getLongName;
private readSessionFromPayload;
private get refreshTokenHeader();
}

8

package.json
{
"name": "@a-type/auth",
"version": "0.3.7",
"version": "0.3.8",
"description": "My personal auth request handlers",

@@ -30,3 +30,4 @@ "module": "dist/esm/index.js",

"@types/simple-oauth2": "^5.0.7",
"typescript": "^5.0.2"
"typescript": "^5.0.2",
"vitest": "1.3.1"
},

@@ -40,4 +41,5 @@ "keywords": [],

"ci:version": "pnpm changeset version",
"ci:publish": "pnpm changeset publish --access=public"
"ci:publish": "pnpm changeset publish --access=public",
"test": "vitest"
}
}

@@ -339,2 +339,13 @@ import { AuthDB } from './db.js';

async function handleRefreshSessionRequest(req: Request) {
const accessToken = sessions.getAccessToken(req);
const refreshToken = sessions.getRefreshToken(req);
if (!accessToken || !refreshToken) {
throw new AuthError('Invalid session', 401);
}
return sessions.refreshSession(accessToken, refreshToken);
}
return {

@@ -350,3 +361,4 @@ handleOAuthLoginRequest,

handleSessionRequest,
handleRefreshSessionRequest,
};
}
import { parse } from 'cookie';
import { SignJWT, jwtVerify, errors } from 'jose';
import {
SignJWT,
jwtVerify,
decodeJwt,
errors,
JWTPayload,
compactVerify,
} from 'jose';
import { AuthError } from './error.js';
import { randomUUID } from 'crypto';

@@ -25,2 +33,3 @@ export interface Session {

cookieName: string;
refreshTokenHeader?: string;
shortNames: ShortNames;

@@ -49,3 +58,3 @@ mode?: 'production' | 'development';

getSession = async (req: Request) => {
getAccessToken = (req: { headers: Headers }) => {
const cookieHeader = req.headers.get('cookie') ?? '';

@@ -57,2 +66,13 @@ const cookies = parse(cookieHeader);

}
return cookieValue;
};
getRefreshToken = (req: { headers: Headers }) => {
return req.headers.get(this.refreshTokenHeader);
};
getSession = async (req: { headers: Headers }) => {
const cookieValue = this.getAccessToken(req);
if (!cookieValue) return null;
// read the JWT from the cookie

@@ -65,8 +85,3 @@ try {

// convert the JWT claims to a session object
const session: Session = Object.fromEntries(
Object.entries(jwt.payload).map(([key, value]) => [
this.getLongName(key),
value,
]),
) as any;
const session: Session = this.readSessionFromPayload(jwt.payload);
// in dev mode, validate session has the right keys

@@ -98,3 +113,57 @@ if (this.options.mode === 'development') {

updateSession = async (session: Session): Promise<Record<string, string>> => {
/**
* Refresh the session by re-signing the JWT with a new expiration time.
* Requires a valid refresh token.
*/
refreshSession = async (
accessToken: string,
refreshToken: string,
): Promise<Record<string, string>> => {
const refreshData = await jwtVerify(refreshToken, this.secret, {
issuer: this.options.issuer,
audience: this.options.audience,
});
// verify the signature of the token
await compactVerify(accessToken, this.secret);
const accessData = decodeJwt(accessToken);
if (refreshData.payload.jti !== accessData.jti) {
throw new AuthError('Invalid refresh token', 400);
}
const session = this.readSessionFromPayload(accessData);
return this.updateSession(session, { sendRefreshToken: true });
};
updateSession = async (
session: Session,
{ sendRefreshToken } = { sendRefreshToken: false },
): Promise<Record<string, string>> => {
const jti = randomUUID();
const accessTokenBuilder = this.getAccessTokenBuilder(session, jti);
const jwt = await accessTokenBuilder.sign(this.secret);
const headers: Record<string, string> = {
'Set-Cookie': `${this.options.cookieName}=${jwt}; Path=/; HttpOnly; SameSite=Strict`,
};
if (sendRefreshToken) {
const refreshTokenBuilder = this.getRefreshTokenBuilder(jti);
const refreshToken = await refreshTokenBuilder.sign(this.secret);
headers[this.refreshTokenHeader] = refreshToken;
}
return headers;
};
clearSession = (): Record<string, string> => {
return {
'Set-Cookie': `${this.options.cookieName}=; Path=/; HttpOnly; SameSite=Strict; Max-Age=0`,
};
};
private getAccessTokenBuilder = (session: Session, jti: string) => {
const builder = new SignJWT(

@@ -111,3 +180,4 @@ Object.fromEntries(

.setExpirationTime(this.options.expiration ?? '12h')
.setSubject(session.userId);
.setSubject(session.userId)
.setJti(jti);

@@ -120,13 +190,21 @@ if (this.options.issuer) {

}
const jwt = await builder.sign(this.secret);
return {
'Set-Cookie': `${this.options.cookieName}=${jwt}; Path=/; HttpOnly; SameSite=Strict`,
};
return builder;
};
clearSession = (): Record<string, string> => {
return {
'Set-Cookie': `${this.options.cookieName}=; Path=/; HttpOnly; SameSite=Strict; Max-Age=0`,
};
private getRefreshTokenBuilder = (jti: string) => {
const refreshTokenBuilder = new SignJWT({
jti,
})
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('7d');
if (this.options.issuer) {
refreshTokenBuilder.setIssuer(this.options.issuer);
}
if (this.options.audience) {
refreshTokenBuilder.setAudience(this.options.audience);
}
return refreshTokenBuilder;
};

@@ -140,2 +218,12 @@

};
private readSessionFromPayload = (jwt: JWTPayload): Session => {
return Object.fromEntries(
Object.entries(jwt).map(([key, value]) => [this.getLongName(key), value]),
) as any;
};
private get refreshTokenHeader() {
return this.options.refreshTokenHeader ?? 'x-refresh-token';
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc