diff --git a/services/mana-core-auth/src/auth/better-auth.config.ts b/services/mana-core-auth/src/auth/better-auth.config.ts index 13efe856f..055928126 100644 --- a/services/mana-core-auth/src/auth/better-auth.config.ts +++ b/services/mana-core-auth/src/auth/better-auth.config.ts @@ -91,8 +91,8 @@ export function createBetterAuth(databaseUrl: string) { * Password Reset Configuration * * Better Auth provides password reset via: - * - auth.api.forgetPassword({ email }) - Sends reset email - * - auth.api.resetPassword({ newPassword, token }) - Resets password + * - auth.api.requestPasswordReset({ body: { email } }) - Sends reset email + * - auth.api.resetPassword({ body: { newPassword, token } }) - Resets password * * @see https://www.better-auth.com/docs/authentication/email-password#password-reset */ diff --git a/services/mana-core-auth/src/auth/services/better-auth.service.ts b/services/mana-core-auth/src/auth/services/better-auth.service.ts index 25a1be0fc..af67d68a6 100644 --- a/services/mana-core-auth/src/auth/services/better-auth.service.ts +++ b/services/mana-core-auth/src/auth/services/better-auth.service.ts @@ -56,11 +56,8 @@ import type { OrganizationMember, Organization, BetterAuthAPI, - SignUpResponse, - SignInResponse, CreateOrganizationResponse, BetterAuthUser, - BetterAuthSession, } from '../types/better-auth.types'; import * as jwt from 'jsonwebtoken'; import { jwtVerify, createRemoteJWKSet } from 'jose'; @@ -89,11 +86,13 @@ export class BetterAuthService { private databaseUrl: string; /** - * Typed accessor for organization plugin API methods - * Better Auth's organization plugin adds methods dynamically, so we provide + * Typed accessor for Better Auth API methods + * Better Auth's plugins add methods dynamically, so we provide * a typed accessor to avoid casting throughout the service. + * + * @see https://www.better-auth.com/docs/concepts/typescript */ - private get orgApi(): BetterAuthAPI { + private get api(): BetterAuthAPI { return this.auth.api as unknown as BetterAuthAPI; } @@ -245,7 +244,7 @@ export class BetterAuthService { try { // Better Auth organization plugin uses auth.api.inviteMember // See: https://www.better-auth.com/docs/plugins/organization - const result = await this.orgApi.inviteMember({ + const result = await this.api.inviteMember({ body: { email: dto.employeeEmail, role: dto.role, @@ -286,7 +285,7 @@ export class BetterAuthService { try { // Better Auth organization plugin uses auth.api.acceptInvitation // See: https://www.better-auth.com/docs/plugins/organization - const result = await this.orgApi.acceptInvitation({ + const result = await this.api.acceptInvitation({ body: { invitationId: dto.invitationId }, headers: { authorization: `Bearer ${dto.userToken}`, @@ -324,7 +323,7 @@ export class BetterAuthService { try { // Better Auth uses getFullOrganization to get org with members // See: https://www.better-auth.com/docs/plugins/organization - const result = await this.orgApi.getFullOrganization({ + const result = await this.api.getFullOrganization({ query: { organizationId }, }); @@ -353,7 +352,7 @@ export class BetterAuthService { // Better Auth organization plugin uses auth.api.removeMember // Accepts memberIdOrEmail parameter // See: https://www.better-auth.com/docs/plugins/organization - await this.orgApi.removeMember({ + await this.api.removeMember({ body: { memberIdOrEmail: dto.memberId, organizationId: dto.organizationId, @@ -388,7 +387,7 @@ export class BetterAuthService { try { // Better Auth organization plugin uses auth.api.setActiveOrganization // See: https://www.better-auth.com/docs/plugins/organization - const result = await this.orgApi.setActiveOrganization({ + const result = await this.api.setActiveOrganization({ body: { organizationId: dto.organizationId }, headers: { authorization: `Bearer ${dto.userToken}`, @@ -441,10 +440,8 @@ export class BetterAuthService { // Generate JWT access token using Better Auth's JWT plugin let accessToken = ''; try { - const api = this.auth.api as any; - // Use Better Auth's signJWT with the jwks table - const jwtResult = await api.signJWT({ + const jwtResult = await this.api.signJWT({ body: { payload: { sub: user.id, @@ -537,7 +534,7 @@ export class BetterAuthService { async signOut(token: string): Promise { try { // Better Auth uses auth.api.signOut - await (this.auth.api as any).signOut({ + await this.api.signOut({ headers: { authorization: `Bearer ${token}`, }, @@ -564,7 +561,7 @@ export class BetterAuthService { async getSession(token: string): Promise { try { // Better Auth uses auth.api.getSession - const result = await (this.auth.api as any).getSession({ + const result = await this.api.getSession({ headers: { authorization: `Bearer ${token}`, }, @@ -602,7 +599,7 @@ export class BetterAuthService { */ async listOrganizations(token: string): Promise { try { - const result = await this.orgApi.listOrganizations({ + const result = await this.api.listOrganizations({ headers: { authorization: `Bearer ${token}`, }, @@ -633,7 +630,7 @@ export class BetterAuthService { token?: string ): Promise { try { - const result = await this.orgApi.getFullOrganization({ + const result = await this.api.getFullOrganization({ query: { organizationId }, ...(token && { headers: { @@ -864,9 +861,9 @@ export class BetterAuthService { redirectTo?: string ): Promise<{ success: boolean; message: string }> { try { - // Better Auth's forgetPassword method + // Better Auth's requestPasswordReset method // See: https://www.better-auth.com/docs/authentication/email-password#password-reset - await (this.auth.api as any).forgetPassword({ + await this.api.requestPasswordReset({ body: { email, redirectTo, @@ -906,7 +903,7 @@ export class BetterAuthService { try { // Better Auth's resetPassword method // See: https://www.better-auth.com/docs/authentication/email-password#password-reset - await (this.auth.api as any).resetPassword({ + await this.api.resetPassword({ body: { token, newPassword, @@ -941,12 +938,9 @@ export class BetterAuthService { */ async getJwks(): Promise<{ keys: unknown[] }> { try { - // Better Auth exposes JWKS via auth.api - const api = this.auth.api as any; - // Try to get JWKS from Better Auth - if (api.getJwks) { - const result = await api.getJwks(); + const result = await this.api.getJwks(); + if (result) { return result; } diff --git a/services/mana-core-auth/src/auth/types/better-auth.types.ts b/services/mana-core-auth/src/auth/types/better-auth.types.ts index 2fca555b4..c8c352c10 100644 --- a/services/mana-core-auth/src/auth/types/better-auth.types.ts +++ b/services/mana-core-auth/src/auth/types/better-auth.types.ts @@ -268,11 +268,29 @@ export interface AuthenticatedRequest { * * This interface describes the methods available on auth.api * when using the organization plugin. + * + * @see https://www.better-auth.com/docs/concepts/typescript */ export interface BetterAuthAPI { // Core auth methods signUpEmail(params: { body: SignUpEmailBody }): Promise; signInEmail(params: { body: { email: string; password: string } }): Promise; + signOut(params: AuthenticatedRequest): Promise<{ success: boolean }>; + getSession( + params: AuthenticatedRequest + ): Promise<{ user: BetterAuthUser; session: BetterAuthSession }>; + + // Password reset methods + requestPasswordReset(params: { + body: { email: string; redirectTo?: string }; + }): Promise<{ status: boolean }>; + resetPassword(params: { + body: { newPassword: string; token: string }; + }): Promise<{ status: boolean }>; + + // JWT methods + signJWT(params: { body: { payload: Record } }): Promise<{ token: string }>; + getJwks(): Promise<{ keys: unknown[] }>; // Organization methods createOrganization(