@oktis-works/auth 0.1.0

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.
@@ -0,0 +1,10 @@
1
+ export { AuthService } from './service.js';
2
+ export type { AuthResult, RegisterInput, LoginInput } from './service.js';
3
+ export { JWTService } from './jwt/index.js';
4
+ export type { TokenPayload, TokenPair } from './jwt/index.js';
5
+ export { RBACService } from './rbac/index.js';
6
+ export type { Permission, RolePermissions, RBACPolicy } from './rbac/index.js';
7
+ export { SessionService } from './sessions/index.js';
8
+ export type { Session } from './sessions/index.js';
9
+ export { hashPassword, verifyPassword } from './password/index.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ // @oktis-works/auth - Main Entry Point
2
+ export { AuthService } from './service.js';
3
+ export { JWTService } from './jwt/index.js';
4
+ export { RBACService } from './rbac/index.js';
5
+ export { SessionService } from './sessions/index.js';
6
+ export { hashPassword, verifyPassword } from './password/index.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AAEvC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { AuthConfig } from '@oktis-works/config';
2
+ export interface TokenPayload {
3
+ sub: string;
4
+ email: string;
5
+ tenantId: string;
6
+ roles: string[];
7
+ iat: number;
8
+ exp: number;
9
+ }
10
+ export interface TokenPair {
11
+ accessToken: string;
12
+ refreshToken: string;
13
+ }
14
+ export declare class JWTService {
15
+ private config;
16
+ constructor(config: AuthConfig);
17
+ generateTokenPair(payload: Omit<TokenPayload, 'iat' | 'exp'>): Promise<TokenPair>;
18
+ verifyToken(token: string): Promise<TokenPayload | null>;
19
+ refreshAccessToken(refreshToken: string): Promise<TokenPair | null>;
20
+ private sign;
21
+ }
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/jwt/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAmDD,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAa;gBAEf,MAAM,EAAE,UAAU;IAIxB,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,KAAK,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;IAuBjF,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAuBxD,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;YAY3D,IAAI;CAOnB"}
@@ -0,0 +1,98 @@
1
+ // @oktis-works/auth - JWT Token Management
2
+ async function hmacSign(data, secret) {
3
+ const encoder = new TextEncoder();
4
+ const keyData = encoder.encode(secret);
5
+ const key = await crypto.subtle.importKey('raw', keyData, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
6
+ const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data));
7
+ return Buffer.from(signature).toString('base64url');
8
+ }
9
+ async function hmacVerify(data, signature, secret) {
10
+ const encoder = new TextEncoder();
11
+ const keyData = encoder.encode(secret);
12
+ const key = await crypto.subtle.importKey('raw', keyData, { name: 'HMAC', hash: 'SHA-256' }, false, ['verify']);
13
+ const sigBuffer = Buffer.from(signature, 'base64url');
14
+ return crypto.subtle.verify('HMAC', key, sigBuffer, encoder.encode(data));
15
+ }
16
+ function base64urlEncode(data) {
17
+ return Buffer.from(data).toString('base64url');
18
+ }
19
+ function base64urlDecode(data) {
20
+ return Buffer.from(data, 'base64url').toString();
21
+ }
22
+ function parseDuration(str) {
23
+ const match = str.match(/^(\d+)([smhd])$/);
24
+ if (!match)
25
+ return 900;
26
+ const num = parseInt(match[1], 10);
27
+ switch (match[2]) {
28
+ case 's': return num;
29
+ case 'm': return num * 60;
30
+ case 'h': return num * 3600;
31
+ case 'd': return num * 86400;
32
+ default: return 900;
33
+ }
34
+ }
35
+ export class JWTService {
36
+ config;
37
+ constructor(config) {
38
+ this.config = config;
39
+ }
40
+ async generateTokenPair(payload) {
41
+ const now = Math.floor(Date.now() / 1000);
42
+ const expiresIn = parseDuration(this.config.jwtExpiresIn);
43
+ const refreshExpiresIn = parseDuration(this.config.refreshTokenExpiresIn);
44
+ const accessToken = {
45
+ ...payload,
46
+ iat: now,
47
+ exp: now + expiresIn,
48
+ };
49
+ const refreshToken = {
50
+ ...payload,
51
+ iat: now,
52
+ exp: now + refreshExpiresIn,
53
+ };
54
+ return {
55
+ accessToken: await this.sign(accessToken),
56
+ refreshToken: await this.sign(refreshToken),
57
+ };
58
+ }
59
+ async verifyToken(token) {
60
+ try {
61
+ const parts = token.split('.');
62
+ if (parts.length !== 3)
63
+ return null;
64
+ const [header, payload, signature] = parts;
65
+ const data = `${header}.${payload}`;
66
+ const valid = await hmacVerify(data, signature, this.config.jwtSecret);
67
+ if (!valid)
68
+ return null;
69
+ const decoded = JSON.parse(base64urlDecode(payload));
70
+ if (decoded.exp < Math.floor(Date.now() / 1000)) {
71
+ return null;
72
+ }
73
+ return decoded;
74
+ }
75
+ catch {
76
+ return null;
77
+ }
78
+ }
79
+ async refreshAccessToken(refreshToken) {
80
+ const payload = await this.verifyToken(refreshToken);
81
+ if (!payload)
82
+ return null;
83
+ return this.generateTokenPair({
84
+ sub: payload.sub,
85
+ email: payload.email,
86
+ tenantId: payload.tenantId,
87
+ roles: payload.roles,
88
+ });
89
+ }
90
+ async sign(payload) {
91
+ const header = base64urlEncode(JSON.stringify({ alg: 'HS256', typ: 'JWT' }));
92
+ const body = base64urlEncode(JSON.stringify(payload));
93
+ const data = `${header}.${body}`;
94
+ const signature = await hmacSign(data, this.config.jwtSecret);
95
+ return `${data}.${signature}`;
96
+ }
97
+ }
98
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/jwt/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function hashPassword(password: string): Promise<string>;
2
+ export declare function verifyPassword(password: string, hash: string): Promise<boolean>;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/password/index.ts"],"names":[],"mappings":"AAEA,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BpE;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA0CrF"}
@@ -0,0 +1,46 @@
1
+ // @oktis-works/auth - Password Hashing
2
+ export async function hashPassword(password) {
3
+ const encoder = new TextEncoder();
4
+ const data = encoder.encode(password);
5
+ // Use Web Crypto API (available in Node 15+)
6
+ const salt = crypto.getRandomValues(new Uint8Array(16));
7
+ const key = await crypto.subtle.importKey('raw', data, { name: 'PBKDF2' }, false, ['deriveBits']);
8
+ const bits = await crypto.subtle.deriveBits({
9
+ name: 'PBKDF2',
10
+ hash: 'SHA-256',
11
+ salt,
12
+ iterations: 100000,
13
+ }, key, 256);
14
+ const hashArray = new Uint8Array(bits);
15
+ const saltArray = new Uint8Array(salt);
16
+ // Format: $algorithm$iterations$salt$hash
17
+ return `$pbkdf2-sha256$100000$${Buffer.from(saltArray).toString('base64')}$${Buffer.from(hashArray).toString('base64')}`;
18
+ }
19
+ export async function verifyPassword(password, hash) {
20
+ const parts = hash.split('$');
21
+ if (parts.length !== 5 || parts[1] !== 'pbkdf2-sha256') {
22
+ throw new Error('Invalid hash format');
23
+ }
24
+ const iterations = parseInt(parts[2], 10);
25
+ const salt = Buffer.from(parts[3], 'base64');
26
+ const expectedHash = Buffer.from(parts[4], 'base64');
27
+ const encoder = new TextEncoder();
28
+ const data = encoder.encode(password);
29
+ const key = await crypto.subtle.importKey('raw', data, { name: 'PBKDF2' }, false, ['deriveBits']);
30
+ const bits = await crypto.subtle.deriveBits({
31
+ name: 'PBKDF2',
32
+ hash: 'SHA-256',
33
+ salt,
34
+ iterations,
35
+ }, key, 256);
36
+ const computedHash = new Uint8Array(bits);
37
+ // Constant-time comparison
38
+ if (computedHash.length !== expectedHash.length)
39
+ return false;
40
+ for (let i = 0; i < computedHash.length; i++) {
41
+ if (computedHash[i] !== expectedHash[i])
42
+ return false;
43
+ }
44
+ return true;
45
+ }
46
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/password/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export interface Permission {
2
+ action: string;
3
+ resource: string;
4
+ conditions?: Record<string, unknown>;
5
+ }
6
+ export interface RolePermissions {
7
+ role: string;
8
+ permissions: Permission[];
9
+ }
10
+ export interface RBACPolicy {
11
+ roles: RolePermissions[];
12
+ inheritance: Record<string, string[]>;
13
+ }
14
+ export declare class RBACService {
15
+ private policy;
16
+ constructor(policy?: RBACPolicy);
17
+ hasPermission(userRoles: string[], action: string, resource: string, context?: Record<string, unknown>): boolean;
18
+ getUserPermissions(userRoles: string[]): Permission[];
19
+ private resolvePermissions;
20
+ private checkConditions;
21
+ }
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rbac/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACvC;AAwDD,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAa;gBAEf,MAAM,CAAC,EAAE,UAAU;IAI/B,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IAqBhH,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE;IAIrD,OAAO,CAAC,kBAAkB;IA2B1B,OAAO,CAAC,eAAe;CAYxB"}
@@ -0,0 +1,116 @@
1
+ // @oktis-works/auth - Role-Based Access Control
2
+ const DEFAULT_POLICY = {
3
+ roles: [
4
+ {
5
+ role: 'SUPER_ADMIN',
6
+ permissions: [{ action: '*', resource: '*' }],
7
+ },
8
+ {
9
+ role: 'TENANT_ADMIN',
10
+ permissions: [
11
+ { action: '*', resource: 'tenant' },
12
+ { action: '*', resource: 'user' },
13
+ { action: '*', resource: 'role' },
14
+ { action: '*', resource: 'content' },
15
+ { action: '*', resource: 'media' },
16
+ { action: '*', resource: 'plugin' },
17
+ { action: '*', resource: 'theme' },
18
+ { action: '*', resource: 'setting' },
19
+ ],
20
+ },
21
+ {
22
+ role: 'EDITOR',
23
+ permissions: [
24
+ { action: 'read', resource: 'content' },
25
+ { action: 'create', resource: 'content' },
26
+ { action: 'update', resource: 'content' },
27
+ { action: 'read', resource: 'media' },
28
+ { action: 'upload', resource: 'media' },
29
+ ],
30
+ },
31
+ {
32
+ role: 'AUTHOR',
33
+ permissions: [
34
+ { action: 'read', resource: 'content' },
35
+ { action: 'create', resource: 'content' },
36
+ { action: 'update', resource: 'content', conditions: { own: true } },
37
+ { action: 'read', resource: 'media' },
38
+ { action: 'upload', resource: 'media' },
39
+ ],
40
+ },
41
+ {
42
+ role: 'VIEWER',
43
+ permissions: [
44
+ { action: 'read', resource: 'content' },
45
+ { action: 'read', resource: 'media' },
46
+ ],
47
+ },
48
+ ],
49
+ inheritance: {
50
+ TENANT_ADMIN: ['EDITOR'],
51
+ EDITOR: ['AUTHOR'],
52
+ AUTHOR: ['VIEWER'],
53
+ },
54
+ };
55
+ export class RBACService {
56
+ policy;
57
+ constructor(policy) {
58
+ this.policy = policy ?? DEFAULT_POLICY;
59
+ }
60
+ hasPermission(userRoles, action, resource, context) {
61
+ const allPermissions = this.resolvePermissions(userRoles);
62
+ return allPermissions.some(permission => {
63
+ // Check action match
64
+ const actionMatch = permission.action === '*' || permission.action === action;
65
+ if (!actionMatch)
66
+ return false;
67
+ // Check resource match
68
+ const resourceMatch = permission.resource === '*' || permission.resource === resource;
69
+ if (!resourceMatch)
70
+ return false;
71
+ // Check conditions
72
+ if (permission.conditions && context) {
73
+ return this.checkConditions(permission.conditions, context);
74
+ }
75
+ return true;
76
+ });
77
+ }
78
+ getUserPermissions(userRoles) {
79
+ return this.resolvePermissions(userRoles);
80
+ }
81
+ resolvePermissions(roles) {
82
+ const permissions = [];
83
+ const visited = new Set();
84
+ const resolve = (role) => {
85
+ if (visited.has(role))
86
+ return;
87
+ visited.add(role);
88
+ const rolePerms = this.policy.roles.find(r => r.role === role);
89
+ if (rolePerms) {
90
+ permissions.push(...rolePerms.permissions);
91
+ }
92
+ // Resolve inherited roles
93
+ const inherited = this.policy.inheritance[role] ?? [];
94
+ for (const inheritedRole of inherited) {
95
+ resolve(inheritedRole);
96
+ }
97
+ };
98
+ for (const role of roles) {
99
+ resolve(role);
100
+ }
101
+ return permissions;
102
+ }
103
+ checkConditions(conditions, context) {
104
+ for (const [key, value] of Object.entries(conditions)) {
105
+ if (key === 'own') {
106
+ // Check if the user owns the resource
107
+ if (value === true && context['userId'] !== context['resourceOwnerId']) {
108
+ return false;
109
+ }
110
+ }
111
+ // Add more condition checks as needed
112
+ }
113
+ return true;
114
+ }
115
+ }
116
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rbac/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { AuthConfig } from '@oktis-works/config';
2
+ import type { User } from '@oktis-works/types';
3
+ export interface AuthResult {
4
+ user: User;
5
+ accessToken: string;
6
+ refreshToken: string;
7
+ sessionId: string;
8
+ }
9
+ export interface RegisterInput {
10
+ email: string;
11
+ password: string;
12
+ name: string;
13
+ }
14
+ export interface LoginInput {
15
+ email: string;
16
+ password: string;
17
+ tenantId: string;
18
+ ipAddress?: string;
19
+ userAgent?: string;
20
+ }
21
+ export declare class AuthService {
22
+ private jwt;
23
+ private session;
24
+ private rbac;
25
+ private config;
26
+ constructor(config: AuthConfig);
27
+ register(input: RegisterInput): Promise<User>;
28
+ login(input: LoginInput): Promise<AuthResult>;
29
+ refreshToken(refreshToken: string): Promise<{
30
+ accessToken: string;
31
+ refreshToken: string;
32
+ } | null>;
33
+ logout(token: string): Promise<void>;
34
+ verifyToken(token: string): Promise<import("./index.js").TokenPayload | null>;
35
+ hasPermission(userRoles: string[], action: string, resource: string, context?: Record<string, unknown>): boolean;
36
+ getUserPermissions(userRoles: string[]): import("./index.js").Permission[];
37
+ }
38
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAM/C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,IAAI,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,MAAM,CAAa;gBAEf,MAAM,EAAE,UAAU;IAOxB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB7C,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAoD7C,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAOjG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpC,WAAW,CAAC,KAAK,EAAE,MAAM;IAI/B,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IAIhH,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE;CAGvC"}
@@ -0,0 +1,86 @@
1
+ // @oktis-works/auth - Authentication Service
2
+ import { randomUUID } from 'node:crypto';
3
+ import { getConnection } from '@oktis-works/database';
4
+ import { hashPassword, verifyPassword } from './password/index.js';
5
+ import { JWTService } from './jwt/index.js';
6
+ import { SessionService } from './sessions/index.js';
7
+ import { RBACService } from './rbac/index.js';
8
+ export class AuthService {
9
+ jwt;
10
+ session;
11
+ rbac;
12
+ config;
13
+ constructor(config) {
14
+ this.config = config;
15
+ this.jwt = new JWTService(config);
16
+ this.session = new SessionService();
17
+ this.rbac = new RBACService();
18
+ }
19
+ async register(input) {
20
+ const sql = getConnection();
21
+ const existing = await sql.unsafe('SELECT id FROM users WHERE email = $1', [input.email]);
22
+ if (existing.length > 0) {
23
+ throw new Error('User with this email already exists');
24
+ }
25
+ const passwordHash = await hashPassword(input.password);
26
+ const result = await sql.unsafe(`INSERT INTO users (id, email, name, password_hash, status)
27
+ VALUES ($1, $2, $3, $4, 'ACTIVE')
28
+ RETURNING *`, [randomUUID(), input.email, input.name, passwordHash]);
29
+ return result[0];
30
+ }
31
+ async login(input) {
32
+ const sql = getConnection();
33
+ const users = await sql.unsafe('SELECT * FROM users WHERE email = $1 AND status = $2', [input.email, 'ACTIVE']);
34
+ if (users.length === 0) {
35
+ throw new Error('Invalid credentials');
36
+ }
37
+ const user = users[0];
38
+ const valid = await verifyPassword(input.password, user.passwordHash);
39
+ if (!valid) {
40
+ throw new Error('Invalid credentials');
41
+ }
42
+ const roles = await sql.unsafe(`SELECT r.slug
43
+ FROM roles r
44
+ JOIN tenant_users tu ON tu.role_id = r.id
45
+ WHERE tu.user_id = $1
46
+ AND tu.tenant_id = $2
47
+ AND tu.status = 'ACTIVE'`, [user.id, input.tenantId]);
48
+ const userRoles = roles.map((r) => r['slug']);
49
+ const tokens = await this.jwt.generateTokenPair({
50
+ sub: user.id,
51
+ email: user.email,
52
+ tenantId: input.tenantId,
53
+ roles: userRoles,
54
+ });
55
+ const session = await this.session.create(user.id, input.tenantId, {
56
+ ipAddress: input.ipAddress,
57
+ userAgent: input.userAgent,
58
+ });
59
+ await sql.unsafe('UPDATE users SET last_login_at = NOW() WHERE id = $1', [user.id]);
60
+ return {
61
+ user,
62
+ accessToken: tokens.accessToken,
63
+ refreshToken: tokens.refreshToken,
64
+ sessionId: session.id,
65
+ };
66
+ }
67
+ async refreshToken(refreshToken) {
68
+ const payload = await this.jwt.verifyToken(refreshToken);
69
+ if (!payload)
70
+ return null;
71
+ return this.jwt.refreshAccessToken(refreshToken);
72
+ }
73
+ async logout(token) {
74
+ await this.session.delete(token);
75
+ }
76
+ async verifyToken(token) {
77
+ return this.jwt.verifyToken(token);
78
+ }
79
+ hasPermission(userRoles, action, resource, context) {
80
+ return this.rbac.hasPermission(userRoles, action, resource, context);
81
+ }
82
+ getUserPermissions(userRoles) {
83
+ return this.rbac.getUserPermissions(userRoles);
84
+ }
85
+ }
86
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export interface Session {
2
+ id: string;
3
+ userId: string;
4
+ tenantId: string;
5
+ token: string;
6
+ ipAddress?: string;
7
+ userAgent?: string;
8
+ expiresAt: Date;
9
+ createdAt: Date;
10
+ }
11
+ export declare class SessionService {
12
+ create(userId: string, tenantId: string, options?: {
13
+ ipAddress?: string;
14
+ userAgent?: string;
15
+ }): Promise<Session>;
16
+ getByToken(token: string): Promise<Session | null>;
17
+ getById(id: string): Promise<Session | null>;
18
+ delete(token: string): Promise<boolean>;
19
+ deleteAllForUser(userId: string, tenantId: string): Promise<number>;
20
+ cleanup(): Promise<number>;
21
+ }
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sessions/index.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAID,qBAAa,cAAc;IACnB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAehH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IASlD,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAS5C,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMvC,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IASnE,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;CAKjC"}
@@ -0,0 +1,41 @@
1
+ // @oktis-works/auth - Session Management
2
+ import { randomUUID } from 'node:crypto';
3
+ import { getConnection } from '@oktis-works/database';
4
+ const SESSION_EXPIRY_HOURS = 7 * 24; // 7 days default
5
+ export class SessionService {
6
+ async create(userId, tenantId, options) {
7
+ const sql = getConnection();
8
+ const token = randomUUID();
9
+ const expiresAt = new Date(Date.now() + SESSION_EXPIRY_HOURS * 3600 * 1000);
10
+ const result = await sql.unsafe(`INSERT INTO sessions (id, user_id, tenant_id, token, ip_address, user_agent, expires_at)
11
+ VALUES ($1, $2, $3, $4, $5, $6, $7)
12
+ RETURNING *`, [randomUUID(), userId, tenantId, token, options?.ipAddress ?? null, options?.userAgent ?? null, expiresAt.toISOString()]);
13
+ return result[0];
14
+ }
15
+ async getByToken(token) {
16
+ const sql = getConnection();
17
+ const result = await sql.unsafe('SELECT * FROM sessions WHERE token = $1 AND expires_at > NOW()', [token]);
18
+ return result[0] ?? null;
19
+ }
20
+ async getById(id) {
21
+ const sql = getConnection();
22
+ const result = await sql.unsafe('SELECT * FROM sessions WHERE id = $1 AND expires_at > NOW()', [id]);
23
+ return result[0] ?? null;
24
+ }
25
+ async delete(token) {
26
+ const sql = getConnection();
27
+ const result = await sql.unsafe('DELETE FROM sessions WHERE token = $1', [token]);
28
+ return result.count > 0;
29
+ }
30
+ async deleteAllForUser(userId, tenantId) {
31
+ const sql = getConnection();
32
+ const result = await sql.unsafe('DELETE FROM sessions WHERE user_id = $1 AND tenant_id = $2', [userId, tenantId]);
33
+ return result.count;
34
+ }
35
+ async cleanup() {
36
+ const sql = getConnection();
37
+ const result = await sql.unsafe('DELETE FROM sessions WHERE expires_at < NOW()');
38
+ return result.count;
39
+ }
40
+ }
41
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sessions/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAatD,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,iBAAiB;AAEtD,MAAM,OAAO,cAAc;IACzB,KAAK,CAAC,MAAM,CAAC,MAAc,EAAE,QAAgB,EAAE,OAAoD;QACjG,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,oBAAoB,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;QAE5E,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,CAC7B;;mBAEa,EACb,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC,CACzH,CAAC;QAEF,OAAO,MAAM,CAAC,CAAC,CAAuB,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAa;QAC5B,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,CAC7B,gEAAgE,EAChE,CAAC,KAAK,CAAC,CACR,CAAC;QACF,OAAQ,MAAM,CAAC,CAAC,CAAwB,IAAI,IAAI,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,CAC7B,6DAA6D,EAC7D,CAAC,EAAE,CAAC,CACL,CAAC;QACF,OAAQ,MAAM,CAAC,CAAC,CAAwB,IAAI,IAAI,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACxB,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,uCAAuC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAClF,OAAO,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,MAAc,EAAE,QAAgB;QACrD,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,CAC7B,4DAA4D,EAC5D,CAAC,MAAM,EAAE,QAAQ,CAAC,CACnB,CAAC;QACF,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,+CAA+C,CAAC,CAAC;QACjF,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@oktis-works/auth",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "clean": "rm -rf dist tsconfig.tsbuildinfo"
18
+ },
19
+ "dependencies": {
20
+ "@oktis-works/types": "0.1.0",
21
+ "@oktis-works/config": "0.1.0",
22
+ "@oktis-works/database": "0.1.0",
23
+ "@oktis-works/core": "0.1.0"
24
+ },
25
+ "devDependencies": {
26
+ "typescript": "5.7.3",
27
+ "@types/jsonwebtoken": "9.0.0"
28
+ },
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public",
34
+ "registry": "https://registry.npmjs.org/"
35
+ },
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/blacklotus/blacklotus-cms",
40
+ "directory": "packages/auth"
41
+ }
42
+ }