import { Collection, Db } from "mongodb"; import OidcConnection from "../schemas/OidcConnection"; /** * Repository for OIDC connections * * Manages persistent connections between users and OIDC providers. * Stores the mapping of app users to IdP subjects, and optionally * stores encrypted tokens for API access. */ export default class OidcConnectionRepo { private collection: Collection; constructor(collectionName: string, db: Db) { this.collection = db.collection(collectionName); } /** * Create a new OIDC connection * * @param connection - Connection data * @returns Created connection with _id */ async create(connection: Omit): Promise { const result = await this.collection.insertOne(connection as any); return { ...connection, _id: result.insertedId.toString(), }; } /** * Find connection by user ID and provider * * @param userId - Application user ID * @param provider - Provider name * @returns Connection or null if not found */ async findByUserAndProvider(userId: string, provider: string): Promise { const connection = await this.collection.findOne({ userId, provider }); if (!connection) { return null; } return { ...connection, _id: connection._id?.toString(), }; } /** * Find connection by subject and issuer * * Used to look up users by their IdP identity. * * @param subject - OIDC subject (sub claim) * @param issuer - OIDC issuer (iss claim) * @returns Connection or null if not found */ async findBySubjectAndIssuer(subject: string, issuer: string): Promise { const connection = await this.collection.findOne({ subject, issuer }); if (!connection) { return null; } return { ...connection, _id: connection._id?.toString(), }; } /** * Find all connections for a user * * @param userId - Application user ID * @returns Array of connections */ async findByUserId(userId: string): Promise { const connections = await this.collection.find({ userId }).toArray(); return connections.map((conn) => ({ ...conn, _id: conn._id?.toString(), })); } /** * Update connection * * Typically used to update tokens when they're refreshed. * * @param connectionId - Connection _id * @param updates - Fields to update */ async updateOne(connectionId: string, updates: Partial): Promise { await this.collection.updateOne({ _id: connectionId as any }, { $set: updates }); } /** * Delete connection by user and provider * * @param userId - Application user ID * @param provider - Provider name */ async deleteByUserAndProvider(userId: string, provider: string): Promise { await this.collection.deleteOne({ userId, provider }); } /** * Delete all connections for a user * * @param userId - Application user ID */ async deleteByUserId(userId: string): Promise { const result = await this.collection.deleteMany({ userId }); return result.deletedCount; } /** * Find one connection by query * * @param query - MongoDB query * @returns Connection or null if not found */ async getOne(query: Partial): Promise { const connection = await this.collection.findOne(query as any); if (!connection) { return null; } return { ...connection, _id: connection._id?.toString(), }; } }