Fixed build warnings
Some checks failed
armco-org/iam-server-sdk/pipeline/head There was a failure building this commit

This commit is contained in:
2025-12-28 19:20:38 +05:30
parent b483297ab0
commit 309db14f6e
13 changed files with 1162 additions and 4 deletions

62
dist/express.d.mts vendored Normal file
View File

@@ -0,0 +1,62 @@
import { Request, Response, NextFunction } from 'express';
import { AuthenticatedUser, IAMServerConfig, AuthOptions } from './index.mjs';
export { IAMVerifier, createIAMVerifier } from './index.mjs';
/**
* Express middleware for IAM authentication
*/
declare global {
namespace Express {
interface Request {
user?: AuthenticatedUser;
}
}
}
/**
* Create authentication middleware
*
* @example
* ```ts
* import { createAuthMiddleware } from '@armco/iam-server/express';
*
* const auth = createAuthMiddleware({
* issuer: 'http://localhost:5000',
* audience: 'my-api',
* });
*
* // Protect all routes
* app.use('/api', auth());
*
* // Or specific routes
* app.get('/api/users', auth(), (req, res) => {
* console.log(req.user); // AuthenticatedUser
* });
* ```
*/
declare function createAuthMiddleware(config: IAMServerConfig): (options?: AuthOptions) => (req: Request, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>;
/**
* Create role-checking middleware (use after auth middleware)
*
* @example
* ```ts
* app.get('/admin', auth(), requireRole('admin'), handler);
* app.get('/editor', auth(), requireRole(['admin', 'editor']), handler);
* ```
*/
declare function requireRole(roles: string | string[]): (req: Request, res: Response, next: NextFunction) => Response<any, Record<string, any>> | undefined;
/**
* Create scope-checking middleware (use after auth middleware)
*
* @example
* ```ts
* app.get('/data', auth(), requireScope('read:data'), handler);
* ```
*/
declare function requireScope(scopes: string | string[]): (req: Request, res: Response, next: NextFunction) => Response<any, Record<string, any>> | undefined;
/**
* Optional auth - attaches user if token present, but doesn't require it
*/
declare function createOptionalAuthMiddleware(config: IAMServerConfig): (req: Request, res: Response, next: NextFunction) => Promise<void>;
export { AuthOptions, AuthenticatedUser, IAMServerConfig, createAuthMiddleware, createOptionalAuthMiddleware, requireRole, requireScope };

62
dist/express.d.ts vendored Normal file
View File

@@ -0,0 +1,62 @@
import { Request, Response, NextFunction } from 'express';
import { AuthenticatedUser, IAMServerConfig, AuthOptions } from './index.js';
export { IAMVerifier, createIAMVerifier } from './index.js';
/**
* Express middleware for IAM authentication
*/
declare global {
namespace Express {
interface Request {
user?: AuthenticatedUser;
}
}
}
/**
* Create authentication middleware
*
* @example
* ```ts
* import { createAuthMiddleware } from '@armco/iam-server/express';
*
* const auth = createAuthMiddleware({
* issuer: 'http://localhost:5000',
* audience: 'my-api',
* });
*
* // Protect all routes
* app.use('/api', auth());
*
* // Or specific routes
* app.get('/api/users', auth(), (req, res) => {
* console.log(req.user); // AuthenticatedUser
* });
* ```
*/
declare function createAuthMiddleware(config: IAMServerConfig): (options?: AuthOptions) => (req: Request, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>;
/**
* Create role-checking middleware (use after auth middleware)
*
* @example
* ```ts
* app.get('/admin', auth(), requireRole('admin'), handler);
* app.get('/editor', auth(), requireRole(['admin', 'editor']), handler);
* ```
*/
declare function requireRole(roles: string | string[]): (req: Request, res: Response, next: NextFunction) => Response<any, Record<string, any>> | undefined;
/**
* Create scope-checking middleware (use after auth middleware)
*
* @example
* ```ts
* app.get('/data', auth(), requireScope('read:data'), handler);
* ```
*/
declare function requireScope(scopes: string | string[]): (req: Request, res: Response, next: NextFunction) => Response<any, Record<string, any>> | undefined;
/**
* Optional auth - attaches user if token present, but doesn't require it
*/
declare function createOptionalAuthMiddleware(config: IAMServerConfig): (req: Request, res: Response, next: NextFunction) => Promise<void>;
export { AuthOptions, AuthenticatedUser, IAMServerConfig, createAuthMiddleware, createOptionalAuthMiddleware, requireRole, requireScope };

264
dist/express.js vendored Normal file
View File

@@ -0,0 +1,264 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/express/index.ts
var express_exports = {};
__export(express_exports, {
IAMVerifier: () => IAMVerifier,
createAuthMiddleware: () => createAuthMiddleware,
createIAMVerifier: () => createIAMVerifier,
createOptionalAuthMiddleware: () => createOptionalAuthMiddleware,
requireRole: () => requireRole,
requireScope: () => requireScope
});
module.exports = __toCommonJS(express_exports);
// src/verifier.ts
var import_jose = require("jose");
var IAMVerifier = class {
constructor(config) {
this.jwks = null;
this.jwksCreatedAt = 0;
this.config = {
issuer: config.issuer.replace(/\/$/, ""),
audience: config.audience,
cacheKeys: config.cacheKeys ?? true,
cacheTTL: config.cacheTTL ?? 3600,
requiredScopes: config.requiredScopes ?? [],
userIdClaim: config.userIdClaim ?? "sub"
};
}
/**
* Get or create JWKS
*/
getJWKS() {
const now = Date.now();
const ttlMs = this.config.cacheTTL * 1e3;
if (this.jwks && this.config.cacheKeys && now - this.jwksCreatedAt < ttlMs) {
return this.jwks;
}
const jwksUrl = new URL(`${this.config.issuer}/.well-known/jwks.json`);
this.jwks = (0, import_jose.createRemoteJWKSet)(jwksUrl);
this.jwksCreatedAt = now;
return this.jwks;
}
/**
* Verify a JWT token
*/
async verify(token) {
try {
const jwks = this.getJWKS();
const result = await (0, import_jose.jwtVerify)(token, jwks, {
issuer: this.config.issuer,
audience: this.config.audience
});
const payload = result.payload;
if (this.config.requiredScopes.length > 0) {
const tokenScopes = (payload.scope || "").split(" ").filter(Boolean);
const hasRequiredScope = this.config.requiredScopes.some((s) => tokenScopes.includes(s));
if (!hasRequiredScope) {
return {
valid: false,
error: `Missing required scope. Required: ${this.config.requiredScopes.join(", ")}`
};
}
}
return {
valid: true,
payload
};
} catch (error) {
const message = error instanceof Error ? error.message : "Token verification failed";
return {
valid: false,
error: message
};
}
}
/**
* Verify token and extract user info
*/
async authenticate(token) {
const result = await this.verify(token);
if (!result.valid || !result.payload) {
return null;
}
const payload = result.payload;
const scopes = (payload.scope || "").split(" ").filter(Boolean);
return {
id: payload[this.config.userIdClaim] || payload.sub,
userId: payload.userId,
tenantId: payload.tenantId,
email: payload.email,
username: payload.username,
roles: payload.roles || [],
scopes,
claims: payload
};
}
/**
* Check if user has any of the specified scopes
*/
hasScope(user, scopes) {
const required = Array.isArray(scopes) ? scopes : [scopes];
return required.some((scope) => user.scopes.includes(scope));
}
/**
* Check if user has all of the specified scopes
*/
hasAllScopes(user, scopes) {
return scopes.every((scope) => user.scopes.includes(scope));
}
/**
* Check if user has any of the specified roles
*/
hasRole(user, roles) {
const required = Array.isArray(roles) ? roles : [roles];
return required.some((role) => user.roles.includes(role));
}
/**
* Check if user has all of the specified roles
*/
hasAllRoles(user, roles) {
return roles.every((role) => user.roles.includes(role));
}
/**
* Clear JWKS cache (force refresh on next verify)
*/
clearCache() {
this.jwks = null;
this.jwksCreatedAt = 0;
}
};
function createIAMVerifier(config) {
return new IAMVerifier(config);
}
// src/express/index.ts
function extractToken(req) {
const authHeader = req.headers.authorization;
if (!authHeader) return null;
const parts = authHeader.split(" ");
if (parts.length !== 2 || parts[0].toLowerCase() !== "bearer") {
return null;
}
return parts[1];
}
function createAuthMiddleware(config) {
const verifier = createIAMVerifier(config);
return function auth(options = {}) {
return async (req, res, next) => {
const token = extractToken(req);
if (!token) {
return res.status(401).json({
error: "unauthorized",
message: "Missing or invalid Authorization header"
});
}
const user = await verifier.authenticate(token);
if (!user) {
return res.status(401).json({
error: "unauthorized",
message: "Invalid or expired token"
});
}
if (options.scopes && options.scopes.length > 0) {
const hasScope = options.requireAllScopes ? verifier.hasAllScopes(user, options.scopes) : verifier.hasScope(user, options.scopes);
if (!hasScope) {
return res.status(403).json({
error: "forbidden",
message: `Insufficient scope. Required: ${options.scopes.join(", ")}`
});
}
}
if (options.roles && options.roles.length > 0) {
const hasRole = options.requireAllRoles ? verifier.hasAllRoles(user, options.roles) : verifier.hasRole(user, options.roles);
if (!hasRole) {
return res.status(403).json({
error: "forbidden",
message: `Insufficient permissions. Required role: ${options.roles.join(" or ")}`
});
}
}
req.user = user;
next();
};
};
}
function requireRole(roles) {
const required = Array.isArray(roles) ? roles : [roles];
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({
error: "unauthorized",
message: "Authentication required"
});
}
const hasRole = required.some((role) => req.user.roles.includes(role));
if (!hasRole) {
return res.status(403).json({
error: "forbidden",
message: `Required role: ${required.join(" or ")}`
});
}
next();
};
}
function requireScope(scopes) {
const required = Array.isArray(scopes) ? scopes : [scopes];
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({
error: "unauthorized",
message: "Authentication required"
});
}
const hasScope = required.some((scope) => req.user.scopes.includes(scope));
if (!hasScope) {
return res.status(403).json({
error: "forbidden",
message: `Required scope: ${required.join(" or ")}`
});
}
next();
};
}
function createOptionalAuthMiddleware(config) {
const verifier = createIAMVerifier(config);
return async (req, res, next) => {
const token = extractToken(req);
if (token) {
const user = await verifier.authenticate(token);
if (user) {
req.user = user;
}
}
next();
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
IAMVerifier,
createAuthMiddleware,
createIAMVerifier,
createOptionalAuthMiddleware,
requireRole,
requireScope
});
//# sourceMappingURL=express.js.map

1
dist/express.js.map vendored Normal file

File diff suppressed because one or more lines are too long

232
dist/express.mjs vendored Normal file
View File

@@ -0,0 +1,232 @@
// src/verifier.ts
import { createRemoteJWKSet, jwtVerify } from "jose";
var IAMVerifier = class {
constructor(config) {
this.jwks = null;
this.jwksCreatedAt = 0;
this.config = {
issuer: config.issuer.replace(/\/$/, ""),
audience: config.audience,
cacheKeys: config.cacheKeys ?? true,
cacheTTL: config.cacheTTL ?? 3600,
requiredScopes: config.requiredScopes ?? [],
userIdClaim: config.userIdClaim ?? "sub"
};
}
/**
* Get or create JWKS
*/
getJWKS() {
const now = Date.now();
const ttlMs = this.config.cacheTTL * 1e3;
if (this.jwks && this.config.cacheKeys && now - this.jwksCreatedAt < ttlMs) {
return this.jwks;
}
const jwksUrl = new URL(`${this.config.issuer}/.well-known/jwks.json`);
this.jwks = createRemoteJWKSet(jwksUrl);
this.jwksCreatedAt = now;
return this.jwks;
}
/**
* Verify a JWT token
*/
async verify(token) {
try {
const jwks = this.getJWKS();
const result = await jwtVerify(token, jwks, {
issuer: this.config.issuer,
audience: this.config.audience
});
const payload = result.payload;
if (this.config.requiredScopes.length > 0) {
const tokenScopes = (payload.scope || "").split(" ").filter(Boolean);
const hasRequiredScope = this.config.requiredScopes.some((s) => tokenScopes.includes(s));
if (!hasRequiredScope) {
return {
valid: false,
error: `Missing required scope. Required: ${this.config.requiredScopes.join(", ")}`
};
}
}
return {
valid: true,
payload
};
} catch (error) {
const message = error instanceof Error ? error.message : "Token verification failed";
return {
valid: false,
error: message
};
}
}
/**
* Verify token and extract user info
*/
async authenticate(token) {
const result = await this.verify(token);
if (!result.valid || !result.payload) {
return null;
}
const payload = result.payload;
const scopes = (payload.scope || "").split(" ").filter(Boolean);
return {
id: payload[this.config.userIdClaim] || payload.sub,
userId: payload.userId,
tenantId: payload.tenantId,
email: payload.email,
username: payload.username,
roles: payload.roles || [],
scopes,
claims: payload
};
}
/**
* Check if user has any of the specified scopes
*/
hasScope(user, scopes) {
const required = Array.isArray(scopes) ? scopes : [scopes];
return required.some((scope) => user.scopes.includes(scope));
}
/**
* Check if user has all of the specified scopes
*/
hasAllScopes(user, scopes) {
return scopes.every((scope) => user.scopes.includes(scope));
}
/**
* Check if user has any of the specified roles
*/
hasRole(user, roles) {
const required = Array.isArray(roles) ? roles : [roles];
return required.some((role) => user.roles.includes(role));
}
/**
* Check if user has all of the specified roles
*/
hasAllRoles(user, roles) {
return roles.every((role) => user.roles.includes(role));
}
/**
* Clear JWKS cache (force refresh on next verify)
*/
clearCache() {
this.jwks = null;
this.jwksCreatedAt = 0;
}
};
function createIAMVerifier(config) {
return new IAMVerifier(config);
}
// src/express/index.ts
function extractToken(req) {
const authHeader = req.headers.authorization;
if (!authHeader) return null;
const parts = authHeader.split(" ");
if (parts.length !== 2 || parts[0].toLowerCase() !== "bearer") {
return null;
}
return parts[1];
}
function createAuthMiddleware(config) {
const verifier = createIAMVerifier(config);
return function auth(options = {}) {
return async (req, res, next) => {
const token = extractToken(req);
if (!token) {
return res.status(401).json({
error: "unauthorized",
message: "Missing or invalid Authorization header"
});
}
const user = await verifier.authenticate(token);
if (!user) {
return res.status(401).json({
error: "unauthorized",
message: "Invalid or expired token"
});
}
if (options.scopes && options.scopes.length > 0) {
const hasScope = options.requireAllScopes ? verifier.hasAllScopes(user, options.scopes) : verifier.hasScope(user, options.scopes);
if (!hasScope) {
return res.status(403).json({
error: "forbidden",
message: `Insufficient scope. Required: ${options.scopes.join(", ")}`
});
}
}
if (options.roles && options.roles.length > 0) {
const hasRole = options.requireAllRoles ? verifier.hasAllRoles(user, options.roles) : verifier.hasRole(user, options.roles);
if (!hasRole) {
return res.status(403).json({
error: "forbidden",
message: `Insufficient permissions. Required role: ${options.roles.join(" or ")}`
});
}
}
req.user = user;
next();
};
};
}
function requireRole(roles) {
const required = Array.isArray(roles) ? roles : [roles];
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({
error: "unauthorized",
message: "Authentication required"
});
}
const hasRole = required.some((role) => req.user.roles.includes(role));
if (!hasRole) {
return res.status(403).json({
error: "forbidden",
message: `Required role: ${required.join(" or ")}`
});
}
next();
};
}
function requireScope(scopes) {
const required = Array.isArray(scopes) ? scopes : [scopes];
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({
error: "unauthorized",
message: "Authentication required"
});
}
const hasScope = required.some((scope) => req.user.scopes.includes(scope));
if (!hasScope) {
return res.status(403).json({
error: "forbidden",
message: `Required scope: ${required.join(" or ")}`
});
}
next();
};
}
function createOptionalAuthMiddleware(config) {
const verifier = createIAMVerifier(config);
return async (req, res, next) => {
const token = extractToken(req);
if (token) {
const user = await verifier.authenticate(token);
if (user) {
req.user = user;
}
}
next();
};
}
export {
IAMVerifier,
createAuthMiddleware,
createIAMVerifier,
createOptionalAuthMiddleware,
requireRole,
requireScope
};
//# sourceMappingURL=express.mjs.map

1
dist/express.mjs.map vendored Normal file

File diff suppressed because one or more lines are too long

128
dist/index.d.mts vendored Normal file
View File

@@ -0,0 +1,128 @@
/**
* @armco/iam-server Types
*/
interface IAMServerConfig {
/** IAM server base URL (e.g., http://localhost:5000) */
issuer: string;
/** Expected audience (your app's client_id) */
audience: string;
/** Cache JWKS keys (default: true) */
cacheKeys?: boolean;
/** JWKS cache TTL in seconds (default: 3600) */
cacheTTL?: number;
/** Required scopes for all requests (optional) */
requiredScopes?: string[];
/** Custom claim to extract user ID from (default: 'sub') */
userIdClaim?: string;
}
interface JWTPayload {
/** Subject - global identity ID */
sub: string;
/** Issuer */
iss: string;
/** Audience */
aud: string | string[];
/** Issued at */
iat: number;
/** Expiration */
exp: number;
/** User's email */
email?: string;
/** Email verified */
email_verified?: boolean;
/** Username */
username?: string;
/** Tenant ID */
tenantId?: string;
/** User ID (membership ID) */
userId?: string;
/** Roles */
roles?: string[];
/** Scopes */
scope?: string;
/** Additional claims */
[key: string]: unknown;
}
interface VerifyResult {
valid: boolean;
payload?: JWTPayload;
error?: string;
}
interface AuthenticatedUser {
/** Global identity ID (from 'sub' claim) */
id: string;
/** Tenant-specific user ID */
userId?: string;
/** Tenant ID */
tenantId?: string;
/** Email */
email?: string;
/** Username */
username?: string;
/** Roles */
roles: string[];
/** Scopes */
scopes: string[];
/** Raw JWT payload */
claims: JWTPayload;
}
interface AuthOptions {
/** Required scopes (any of these) */
scopes?: string[];
/** Required roles (any of these) */
roles?: string[];
/** Require all specified scopes (default: false - any match) */
requireAllScopes?: boolean;
/** Require all specified roles (default: false - any match) */
requireAllRoles?: boolean;
}
/**
* JWT Verifier using jose library
* Fetches JWKS from IAM and validates tokens
*/
declare class IAMVerifier {
private config;
private jwks;
private jwksCreatedAt;
constructor(config: IAMServerConfig);
/**
* Get or create JWKS
*/
private getJWKS;
/**
* Verify a JWT token
*/
verify(token: string): Promise<VerifyResult>;
/**
* Verify token and extract user info
*/
authenticate(token: string): Promise<AuthenticatedUser | null>;
/**
* Check if user has any of the specified scopes
*/
hasScope(user: AuthenticatedUser, scopes: string | string[]): boolean;
/**
* Check if user has all of the specified scopes
*/
hasAllScopes(user: AuthenticatedUser, scopes: string[]): boolean;
/**
* Check if user has any of the specified roles
*/
hasRole(user: AuthenticatedUser, roles: string | string[]): boolean;
/**
* Check if user has all of the specified roles
*/
hasAllRoles(user: AuthenticatedUser, roles: string[]): boolean;
/**
* Clear JWKS cache (force refresh on next verify)
*/
clearCache(): void;
}
/**
* Create a new IAM verifier instance
*/
declare function createIAMVerifier(config: IAMServerConfig): IAMVerifier;
export { type AuthOptions, type AuthenticatedUser, type IAMServerConfig, IAMVerifier, type JWTPayload, type VerifyResult, createIAMVerifier };

128
dist/index.d.ts vendored Normal file
View File

@@ -0,0 +1,128 @@
/**
* @armco/iam-server Types
*/
interface IAMServerConfig {
/** IAM server base URL (e.g., http://localhost:5000) */
issuer: string;
/** Expected audience (your app's client_id) */
audience: string;
/** Cache JWKS keys (default: true) */
cacheKeys?: boolean;
/** JWKS cache TTL in seconds (default: 3600) */
cacheTTL?: number;
/** Required scopes for all requests (optional) */
requiredScopes?: string[];
/** Custom claim to extract user ID from (default: 'sub') */
userIdClaim?: string;
}
interface JWTPayload {
/** Subject - global identity ID */
sub: string;
/** Issuer */
iss: string;
/** Audience */
aud: string | string[];
/** Issued at */
iat: number;
/** Expiration */
exp: number;
/** User's email */
email?: string;
/** Email verified */
email_verified?: boolean;
/** Username */
username?: string;
/** Tenant ID */
tenantId?: string;
/** User ID (membership ID) */
userId?: string;
/** Roles */
roles?: string[];
/** Scopes */
scope?: string;
/** Additional claims */
[key: string]: unknown;
}
interface VerifyResult {
valid: boolean;
payload?: JWTPayload;
error?: string;
}
interface AuthenticatedUser {
/** Global identity ID (from 'sub' claim) */
id: string;
/** Tenant-specific user ID */
userId?: string;
/** Tenant ID */
tenantId?: string;
/** Email */
email?: string;
/** Username */
username?: string;
/** Roles */
roles: string[];
/** Scopes */
scopes: string[];
/** Raw JWT payload */
claims: JWTPayload;
}
interface AuthOptions {
/** Required scopes (any of these) */
scopes?: string[];
/** Required roles (any of these) */
roles?: string[];
/** Require all specified scopes (default: false - any match) */
requireAllScopes?: boolean;
/** Require all specified roles (default: false - any match) */
requireAllRoles?: boolean;
}
/**
* JWT Verifier using jose library
* Fetches JWKS from IAM and validates tokens
*/
declare class IAMVerifier {
private config;
private jwks;
private jwksCreatedAt;
constructor(config: IAMServerConfig);
/**
* Get or create JWKS
*/
private getJWKS;
/**
* Verify a JWT token
*/
verify(token: string): Promise<VerifyResult>;
/**
* Verify token and extract user info
*/
authenticate(token: string): Promise<AuthenticatedUser | null>;
/**
* Check if user has any of the specified scopes
*/
hasScope(user: AuthenticatedUser, scopes: string | string[]): boolean;
/**
* Check if user has all of the specified scopes
*/
hasAllScopes(user: AuthenticatedUser, scopes: string[]): boolean;
/**
* Check if user has any of the specified roles
*/
hasRole(user: AuthenticatedUser, roles: string | string[]): boolean;
/**
* Check if user has all of the specified roles
*/
hasAllRoles(user: AuthenticatedUser, roles: string[]): boolean;
/**
* Clear JWKS cache (force refresh on next verify)
*/
clearCache(): void;
}
/**
* Create a new IAM verifier instance
*/
declare function createIAMVerifier(config: IAMServerConfig): IAMVerifier;
export { type AuthOptions, type AuthenticatedUser, type IAMServerConfig, IAMVerifier, type JWTPayload, type VerifyResult, createIAMVerifier };

153
dist/index.js vendored Normal file
View File

@@ -0,0 +1,153 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
IAMVerifier: () => IAMVerifier,
createIAMVerifier: () => createIAMVerifier
});
module.exports = __toCommonJS(src_exports);
// src/verifier.ts
var import_jose = require("jose");
var IAMVerifier = class {
constructor(config) {
this.jwks = null;
this.jwksCreatedAt = 0;
this.config = {
issuer: config.issuer.replace(/\/$/, ""),
audience: config.audience,
cacheKeys: config.cacheKeys ?? true,
cacheTTL: config.cacheTTL ?? 3600,
requiredScopes: config.requiredScopes ?? [],
userIdClaim: config.userIdClaim ?? "sub"
};
}
/**
* Get or create JWKS
*/
getJWKS() {
const now = Date.now();
const ttlMs = this.config.cacheTTL * 1e3;
if (this.jwks && this.config.cacheKeys && now - this.jwksCreatedAt < ttlMs) {
return this.jwks;
}
const jwksUrl = new URL(`${this.config.issuer}/.well-known/jwks.json`);
this.jwks = (0, import_jose.createRemoteJWKSet)(jwksUrl);
this.jwksCreatedAt = now;
return this.jwks;
}
/**
* Verify a JWT token
*/
async verify(token) {
try {
const jwks = this.getJWKS();
const result = await (0, import_jose.jwtVerify)(token, jwks, {
issuer: this.config.issuer,
audience: this.config.audience
});
const payload = result.payload;
if (this.config.requiredScopes.length > 0) {
const tokenScopes = (payload.scope || "").split(" ").filter(Boolean);
const hasRequiredScope = this.config.requiredScopes.some((s) => tokenScopes.includes(s));
if (!hasRequiredScope) {
return {
valid: false,
error: `Missing required scope. Required: ${this.config.requiredScopes.join(", ")}`
};
}
}
return {
valid: true,
payload
};
} catch (error) {
const message = error instanceof Error ? error.message : "Token verification failed";
return {
valid: false,
error: message
};
}
}
/**
* Verify token and extract user info
*/
async authenticate(token) {
const result = await this.verify(token);
if (!result.valid || !result.payload) {
return null;
}
const payload = result.payload;
const scopes = (payload.scope || "").split(" ").filter(Boolean);
return {
id: payload[this.config.userIdClaim] || payload.sub,
userId: payload.userId,
tenantId: payload.tenantId,
email: payload.email,
username: payload.username,
roles: payload.roles || [],
scopes,
claims: payload
};
}
/**
* Check if user has any of the specified scopes
*/
hasScope(user, scopes) {
const required = Array.isArray(scopes) ? scopes : [scopes];
return required.some((scope) => user.scopes.includes(scope));
}
/**
* Check if user has all of the specified scopes
*/
hasAllScopes(user, scopes) {
return scopes.every((scope) => user.scopes.includes(scope));
}
/**
* Check if user has any of the specified roles
*/
hasRole(user, roles) {
const required = Array.isArray(roles) ? roles : [roles];
return required.some((role) => user.roles.includes(role));
}
/**
* Check if user has all of the specified roles
*/
hasAllRoles(user, roles) {
return roles.every((role) => user.roles.includes(role));
}
/**
* Clear JWKS cache (force refresh on next verify)
*/
clearCache() {
this.jwks = null;
this.jwksCreatedAt = 0;
}
};
function createIAMVerifier(config) {
return new IAMVerifier(config);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
IAMVerifier,
createIAMVerifier
});
//# sourceMappingURL=index.js.map

1
dist/index.js.map vendored Normal file

File diff suppressed because one or more lines are too long

125
dist/index.mjs vendored Normal file
View File

@@ -0,0 +1,125 @@
// src/verifier.ts
import { createRemoteJWKSet, jwtVerify } from "jose";
var IAMVerifier = class {
constructor(config) {
this.jwks = null;
this.jwksCreatedAt = 0;
this.config = {
issuer: config.issuer.replace(/\/$/, ""),
audience: config.audience,
cacheKeys: config.cacheKeys ?? true,
cacheTTL: config.cacheTTL ?? 3600,
requiredScopes: config.requiredScopes ?? [],
userIdClaim: config.userIdClaim ?? "sub"
};
}
/**
* Get or create JWKS
*/
getJWKS() {
const now = Date.now();
const ttlMs = this.config.cacheTTL * 1e3;
if (this.jwks && this.config.cacheKeys && now - this.jwksCreatedAt < ttlMs) {
return this.jwks;
}
const jwksUrl = new URL(`${this.config.issuer}/.well-known/jwks.json`);
this.jwks = createRemoteJWKSet(jwksUrl);
this.jwksCreatedAt = now;
return this.jwks;
}
/**
* Verify a JWT token
*/
async verify(token) {
try {
const jwks = this.getJWKS();
const result = await jwtVerify(token, jwks, {
issuer: this.config.issuer,
audience: this.config.audience
});
const payload = result.payload;
if (this.config.requiredScopes.length > 0) {
const tokenScopes = (payload.scope || "").split(" ").filter(Boolean);
const hasRequiredScope = this.config.requiredScopes.some((s) => tokenScopes.includes(s));
if (!hasRequiredScope) {
return {
valid: false,
error: `Missing required scope. Required: ${this.config.requiredScopes.join(", ")}`
};
}
}
return {
valid: true,
payload
};
} catch (error) {
const message = error instanceof Error ? error.message : "Token verification failed";
return {
valid: false,
error: message
};
}
}
/**
* Verify token and extract user info
*/
async authenticate(token) {
const result = await this.verify(token);
if (!result.valid || !result.payload) {
return null;
}
const payload = result.payload;
const scopes = (payload.scope || "").split(" ").filter(Boolean);
return {
id: payload[this.config.userIdClaim] || payload.sub,
userId: payload.userId,
tenantId: payload.tenantId,
email: payload.email,
username: payload.username,
roles: payload.roles || [],
scopes,
claims: payload
};
}
/**
* Check if user has any of the specified scopes
*/
hasScope(user, scopes) {
const required = Array.isArray(scopes) ? scopes : [scopes];
return required.some((scope) => user.scopes.includes(scope));
}
/**
* Check if user has all of the specified scopes
*/
hasAllScopes(user, scopes) {
return scopes.every((scope) => user.scopes.includes(scope));
}
/**
* Check if user has any of the specified roles
*/
hasRole(user, roles) {
const required = Array.isArray(roles) ? roles : [roles];
return required.some((role) => user.roles.includes(role));
}
/**
* Check if user has all of the specified roles
*/
hasAllRoles(user, roles) {
return roles.every((role) => user.roles.includes(role));
}
/**
* Clear JWKS cache (force refresh on next verify)
*/
clearCache() {
this.jwks = null;
this.jwksCreatedAt = 0;
}
};
function createIAMVerifier(config) {
return new IAMVerifier(config);
}
export {
IAMVerifier,
createIAMVerifier
};
//# sourceMappingURL=index.mjs.map

1
dist/index.mjs.map vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -7,14 +7,14 @@
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
"require": "./dist/index.js"
},
"./express": {
"types": "./dist/express.d.ts",
"import": "./dist/express.mjs",
"require": "./dist/express.js",
"types": "./dist/express.d.ts"
"require": "./dist/express.js"
}
},
"files": [