feat: api keys

This commit is contained in:
Ahmed Bouhuolia
2025-07-01 23:05:58 +02:00
parent 9f6e9e85a5
commit 84cb7693c8
16 changed files with 266 additions and 8 deletions

View File

@@ -0,0 +1,33 @@
import { Inject, Injectable } from '@nestjs/common';
import { ApiKeyModel } from '../models/ApiKey.model';
@Injectable()
export class AuthApiKeyAuthorizeService {
constructor(
@Inject(ApiKeyModel.name)
private readonly apikeyModel: typeof ApiKeyModel,
) {}
/**
* Authenticate using the given api key.
*/
async authorize(apiKey: string): Promise<boolean> {
const apiKeyRecord = await this.apikeyModel
.query()
.findOne({ key: apiKey });
if (!apiKeyRecord) {
return false;
}
if (apiKeyRecord.revoked) {
return false;
}
if (
apiKeyRecord.expiresAt &&
new Date(apiKeyRecord.expiresAt) < new Date()
) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,41 @@
import { Inject, Injectable } from '@nestjs/common';
import * as crypto from 'crypto';
import { ApiKeyModel } from '../models/ApiKey.model';
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
@Injectable()
export class GenerateApiKey {
constructor(
private readonly tenancyContext: TenancyContext,
@Inject(ApiKeyModel.name)
private readonly apiKeyModel: typeof ApiKeyModel,
) {}
/**
*
* @returns
*/
async generate() {
const tenant = await this.tenancyContext.getTenant();
const user = await this.tenancyContext.getSystemUser();
// Generate a secure random API key
const key = crypto.randomBytes(48).toString('hex');
// Save the API key to the database
const apiKeyRecord = await this.apiKeyModel.query().insert({
key,
tenantId: tenant.id,
userId: user.id,
createdAt: new Date(),
revoked: false,
});
// Return the created API key (not the full record for security)
return { key: apiKeyRecord.key, id: apiKeyRecord.id };
}
async revoke(apiKeyId: number) {
// Set the revoked flag to true for the given API key
await ApiKeyModel.query().findById(apiKeyId).patch({ revoked: true });
return { id: apiKeyId, revoked: true };
}
}