Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/vue-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"build": "vite build && vue-tsc --emitDeclarationOnly",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"prepare": "vite build && vue-tsc --emitDeclarationOnly",
"sort-package": "npx sort-package-json",
"test": "vitest --environment jsdom run --coverage --passWithNoTests",
"test:component": "vitest --environment jsdom run component/ --passWithNoTests",
Expand Down
1 change: 1 addition & 0 deletions packages/vue-form/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"build": "vite build && vue-tsc --emitDeclarationOnly",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"prepare": "vite build && vue-tsc --emitDeclarationOnly",
"snapshot:update": "vitest --environment jsdom run --update",
"sort-package": "npx sort-package-json",
"test": "vitest --environment jsdom run --coverage --passWithNoTests",
Expand Down
1 change: 1 addition & 0 deletions packages/vue-i18n/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"build": "vite build && vue-tsc --emitDeclarationOnly",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"prepare": "vite build && vue-tsc --emitDeclarationOnly",
"snapshot:update": "vitest --environment jsdom run --update",
"sort-package": "npx sort-package-json",
"test": "vitest --environment jsdom run --coverage --passWithNoTests",
Expand Down
1 change: 1 addition & 0 deletions packages/vue-layout/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"build": "vite build && vue-tsc --emitDeclarationOnly",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"prepare": "vite build && vue-tsc --emitDeclarationOnly",
"snapshot:update": "vitest --environment jsdom run --update",
"sort-package": "npx sort-package-json",
"test": "vitest --environment jsdom run --coverage --passWithNoTests",
Expand Down
1 change: 1 addition & 0 deletions packages/vue-tanstack-table/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"build": "vite build && vue-tsc --emitDeclarationOnly",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"prepare": "vite build && vue-tsc --emitDeclarationOnly",
"snapshot:update": "vitest --environment jsdom run --update",
"sort-package": "npx sort-package-json",
"test": "vitest --environment jsdom run --coverage --passWithNoTests",
Expand Down
1 change: 1 addition & 0 deletions packages/vue-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"build": "vite build && vue-tsc --emitDeclarationOnly",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"prepare": "vite build && vue-tsc --emitDeclarationOnly",
"snapshot:update": "vitest --environment jsdom run --update",
"sort-package": "npx sort-package-json",
"test": "vitest --environment jsdom run --coverage --passWithNoTests",
Expand Down
1 change: 1 addition & 0 deletions packages/vue-user/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"build": "vite build && vue-tsc --emitDeclarationOnly",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"prepare": "vite build && vue-tsc --emitDeclarationOnly",
"snapshot:update": "vitest --environment jsdom run --update",
"sort-package": "npx sort-package-json",
"test": "pnpm build && vitest --environment jsdom run --coverage --passWithNoTests",
Expand Down
133 changes: 132 additions & 1 deletion packages/vue-user/src/auth-provider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,31 @@
import {
changeEmail as betterAuthChangeEmail,
changePassword as betterAuthChangePassword,
getVerificationStatus as betterAuthGetVerificationStatus,
isLoggedIn as betterAuthIsLoggedIn,
isProfileCompleted as betterAuthIsProfileCompleted,
login as betterAuthLogin,
logout as betterAuthLogout,
requestPasswordReset as betterAuthRequestPasswordReset,
resetPassword as betterAuthResetPassword,
sendVerificationEmail as betterAuthSendVerificationEmail,
signup as betterAuthSignup,
verifyEmail as betterAuthVerifyEmail,
verifySessionRoles as betterAuthVerifySessionRoles,
} from "./better-auth";
import {
BETTER_AUTH_PATH_CHANGE_EMAIL,
BETTER_AUTH_PATH_CHANGE_PASSWORD,
BETTER_AUTH_PATH_GET_VERIFICATION_STATUS,
BETTER_AUTH_PATH_IS_LOGGED_IN,
BETTER_AUTH_PATH_IS_PROFILE_COMPLETED,
BETTER_AUTH_PATH_LOGIN,
BETTER_AUTH_PATH_LOGOUT,
BETTER_AUTH_PATH_PASSWORD_RESET,
BETTER_AUTH_PATH_PASSWORD_RESET_REQUEST,
BETTER_AUTH_PATH_SEND_VERIFICATION_EMAIL,
BETTER_AUTH_PATH_SIGNUP,
BETTER_AUTH_PATH_VERIFY_EMAIL,
API_PATH_CHANGE_EMAIL,
API_PATH_CHANGE_PASSWORD,
API_PATH_GET_VERIFICATION_STATUS,
Expand Down Expand Up @@ -30,11 +57,12 @@ const initAuthProvider = (config?: AppConfig) => {
const getAuthProvider = () => {
if (
authConfig?.user?.features?.authProvider &&
["laravel-passport", "supertokens"].includes(
["better-auth", "laravel-passport", "supertokens"].includes(
authConfig.user.features.authProvider,
)
) {
return authConfig.user.features.authProvider as
| "better-auth"
| "laravel-passport"
| "supertokens";
}
Expand All @@ -43,6 +71,109 @@ const getAuthProvider = () => {
};

const providers = {
"better-auth": {
doChangeEmail: (email: string) => {
const path =
authConfig?.user?.apiRoutes?.changeEmail ||
BETTER_AUTH_PATH_CHANGE_EMAIL;

return betterAuthChangeEmail(email, authConfig?.apiBaseUrl || "", path);
},
doChangePassword: (payload: ChangePasswordPayload) => {
const path =
authConfig?.user?.apiRoutes?.changePassword ||
BETTER_AUTH_PATH_CHANGE_PASSWORD;

return betterAuthChangePassword(
payload,
authConfig?.apiBaseUrl || "",
path,
);
},
doGetVerificationStatus: () => {
const path =
authConfig?.user?.apiRoutes?.getVerificationStatus ||
BETTER_AUTH_PATH_GET_VERIFICATION_STATUS;

return betterAuthGetVerificationStatus(
authConfig?.apiBaseUrl || "",
path,
);
},
doLogin: (credentials: LoginCredentials) => {
const path = authConfig?.user?.apiRoutes?.login || BETTER_AUTH_PATH_LOGIN;

return betterAuthLogin(credentials, authConfig?.apiBaseUrl || "", path);
},
doLogout: () => {
const path =
authConfig?.user?.apiRoutes?.logout || BETTER_AUTH_PATH_LOGOUT;

return betterAuthLogout(authConfig?.apiBaseUrl || "", path);
},
doRequestPasswordReset: (credentials: PasswordResetRequestPayload) => {
const path =
authConfig?.user?.apiRoutes?.passwordResetRequest ||
BETTER_AUTH_PATH_PASSWORD_RESET_REQUEST;

return betterAuthRequestPasswordReset(
credentials,
authConfig?.apiBaseUrl || "",
path,
);
},
doResetPassword: (credentials: PasswordResetPayload) => {
const path =
authConfig?.user?.apiRoutes?.passwordResetRequest ||
BETTER_AUTH_PATH_PASSWORD_RESET;

return betterAuthResetPassword(
credentials,
authConfig?.apiBaseUrl || "",
path,
);
},
doSendVerificationEmail: () => {
const path =
authConfig?.user?.apiRoutes?.sendVerificationEmail ||
BETTER_AUTH_PATH_SEND_VERIFICATION_EMAIL;

return betterAuthSendVerificationEmail(
authConfig?.apiBaseUrl || "",
path,
);
},
doSignup: (credentials: LoginCredentials) => {
const path =
authConfig?.user?.apiRoutes?.signup || BETTER_AUTH_PATH_SIGNUP;

return betterAuthSignup(credentials, authConfig?.apiBaseUrl || "", path);
},
doVerifyEmail: (token: string) => {
const path =
authConfig?.user?.apiRoutes?.verifyEmail ||
BETTER_AUTH_PATH_VERIFY_EMAIL;

return betterAuthVerifyEmail(token, authConfig?.apiBaseUrl || "", path);
},
isLoggedIn: () => {
const path =
authConfig?.user?.apiRoutes?.isLoggedIn ||
BETTER_AUTH_PATH_IS_LOGGED_IN;

return betterAuthIsLoggedIn(authConfig?.apiBaseUrl || "", path);
},
isProfileCompleted: () => {
const path =
authConfig?.user?.apiRoutes?.isProfileCompleted ||
BETTER_AUTH_PATH_IS_PROFILE_COMPLETED;

return betterAuthIsProfileCompleted(authConfig?.apiBaseUrl || "", path);
},
verifySessionRoles: (claims: string[]) => {
return betterAuthVerifySessionRoles(claims);
},
},
"laravel-passport": {
doChangeEmail: (email: string) => {
const path =
Expand Down
27 changes: 27 additions & 0 deletions packages/vue-user/src/better-auth/change-email.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { AxiosError } from "axios";

import client from "../api/axios";

const changeEmail = async (
email: string,
apiBaseUrl: string,
path: string,
): Promise<void> => {
try {
await client(apiBaseUrl).post(path, {
newEmail: email,
});
} catch (error) {
if (error instanceof AxiosError) {
if (error.response?.status === 409) {
throw new Error("EMAIL_EXISTS");
}

throw new Error("CHANGE_EMAIL_FAILED");
}

throw new Error("CHANGE_EMAIL_FAILED");
}
};

export default changeEmail;
31 changes: 31 additions & 0 deletions packages/vue-user/src/better-auth/change-password.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { AxiosError } from "axios";

import client from "../api/axios";

import type { ChangePasswordPayload } from "../types";

const changePassword = async (
payload: ChangePasswordPayload,
apiBaseUrl: string,
path: string,
): Promise<void> => {
try {
await client(apiBaseUrl).post(path, {
currentPassword: payload.currentPassword,
newPassword: payload.newPassword,
revokeOtherSessions: true,
});
} catch (error) {
if (error instanceof AxiosError) {
if (error.response?.status === 401) {
throw new Error("INVALID_CREDENTIALS");
}

throw new Error("CHANGE_PASSWORD_FAILED");
}

throw new Error("CHANGE_PASSWORD_FAILED");
}
};

export default changePassword;
67 changes: 67 additions & 0 deletions packages/vue-user/src/better-auth/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import client from "../api/axios";
import useUserStore from "../store";

import type { UserType } from "../types/auth";

export async function verifySessionRoles(
supportedRoles: string[],
): Promise<boolean> {
const userStore = useUserStore();
const { logout } = userStore;

const user: UserType | undefined = userStore.getUser();

if (user && user.roles) {
const hasSupportedRoles = await user.roles.some((userRole) => {
if (typeof userRole === "string") {
return supportedRoles.includes(userRole);
}
return supportedRoles.includes(userRole.role);
});

if (hasSupportedRoles) {
return true;
} else {
await logout();
}
} else {
await logout();
}

return false;
}

/**
* Check if user is logged in
* For better-auth, we check if a valid session exists
*/
export const isLoggedIn = async (
apiBaseUrl: string,
path: string,
): Promise<boolean> => {
try {
const response = await client(apiBaseUrl).get(path);

return response.data && response.data.sessionId;
} catch {
return false;
}
};

/**
* Check if user profile is completed
* For better-auth, we can consider profile as completed if user has email
*/
export const isProfileCompleted = async (
apiBaseUrl: string,
path: string,
): Promise<boolean> => {
try {
// Use the same session check endpoint; if session exists, profile is considered complete enough
const response = await client(apiBaseUrl).get(path);

return !!(response.data && response.data.user?.email);
} catch {
return false;
}
};
30 changes: 30 additions & 0 deletions packages/vue-user/src/better-auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import changeEmail from "./change-email";
import changePassword from "./change-password";
import { isLoggedIn, isProfileCompleted, verifySessionRoles } from "./helper";
import login from "./login";
import logout from "./logout";
import requestPasswordReset from "./request-password-reset";
import sendVerificationEmail from "./resend-email-verification";
import resetPassword from "./reset-password";
import sendOtp from "./send-otp";
import signup from "./signup";
import { getVerificationStatus, verifyEmail } from "./verify-email";
import verifyOtp from "./verify-otp";

export {
changeEmail,
changePassword,
getVerificationStatus,
isLoggedIn,
isProfileCompleted,
login,
logout,
requestPasswordReset,
resetPassword,
sendOtp,
sendVerificationEmail,
signup,
verifyEmail,
verifyOtp,
verifySessionRoles,
};
Loading
Loading