docs(auth): add JSDoc comments to OAuth utilities
This commit is contained in:
@@ -42,6 +42,31 @@ export const useAuth = () => {
|
|||||||
return authMethods.oauth2.enabled ? authMethods.oauth2.providers : [];
|
return authMethods.oauth2.enabled ? authMethods.oauth2.providers : [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiates OAuth login flow with the specified provider.
|
||||||
|
*
|
||||||
|
* Handles various error scenarios with user-friendly messages:
|
||||||
|
* - **Unconfigured Provider**: "not configured" in error → Provider not set up in Pocketbase
|
||||||
|
* - **Denied Authorization**: "denied" or "cancel" in error → User cancelled OAuth popup
|
||||||
|
* - **Network Errors**: "network" or "fetch" in error → Connection issues
|
||||||
|
* - **Generic Errors**: All other errors → Fallback message for unexpected failures
|
||||||
|
*
|
||||||
|
* All errors are logged to console with `[useAuth]` prefix for debugging.
|
||||||
|
*
|
||||||
|
* @param provider - The OAuth provider name (e.g., 'google', 'microsoft')
|
||||||
|
* @throws Sets `error.value` with user-friendly message on failure
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* const { login, error } = useAuth()
|
||||||
|
*
|
||||||
|
* await login('google')
|
||||||
|
* if (error.value) {
|
||||||
|
* // Display error.value.message to user
|
||||||
|
* console.log(error.value.message) // "Login was cancelled. Please try again."
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
const login = async (provider: string) => {
|
const login = async (provider: string) => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
error.value = null;
|
error.value = null;
|
||||||
@@ -57,6 +82,7 @@ export const useAuth = () => {
|
|||||||
const err = pbError as Error;
|
const err = pbError as Error;
|
||||||
console.error('[useAuth] Login failed:', err);
|
console.error('[useAuth] Login failed:', err);
|
||||||
|
|
||||||
|
// Error categorization for user-friendly messages
|
||||||
const message = err?.message?.toLowerCase() || '';
|
const message = err?.message?.toLowerCase() || '';
|
||||||
if (message.includes('not configured')) {
|
if (message.includes('not configured')) {
|
||||||
error.value = new Error('This login provider is not available. Contact admin.');
|
error.value = new Error('This login provider is not available. Contact admin.');
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
import { useAuth } from '../composables/useAuth';
|
import { useAuth } from '../composables/useAuth';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication plugin that initializes auth state on app mount (client-side only).
|
||||||
|
*
|
||||||
|
* This plugin automatically:
|
||||||
|
* - Restores the user session from Pocketbase's authStore on page load
|
||||||
|
* - Sets up cross-tab synchronization via Pocketbase's onChange listener
|
||||||
|
* - Enables session persistence across page refreshes
|
||||||
|
*
|
||||||
|
* **Lifecycle**: Runs once on app mount, before any pages are rendered.
|
||||||
|
*
|
||||||
|
* **Cross-Tab Sync**: When a user logs in or out in one browser tab, all other tabs
|
||||||
|
* automatically update their auth state within ~2 seconds (handled by Pocketbase SDK).
|
||||||
|
*
|
||||||
|
* **Session Restoration**: On page refresh, the plugin checks Pocketbase's authStore
|
||||||
|
* and restores the user object if a valid session exists.
|
||||||
|
*
|
||||||
|
* @see {@link useAuth} for the auth composable API
|
||||||
|
*/
|
||||||
export default defineNuxtPlugin(() => {
|
export default defineNuxtPlugin(() => {
|
||||||
const { initAuth } = useAuth();
|
const { initAuth } = useAuth();
|
||||||
initAuth();
|
initAuth();
|
||||||
|
|||||||
@@ -1,3 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Validates a redirect URL to prevent open redirect vulnerabilities.
|
||||||
|
*
|
||||||
|
* Only allows same-origin redirects (paths starting with `/` but not `//`).
|
||||||
|
* External URLs, protocol-relative URLs, and invalid input are rejected.
|
||||||
|
*
|
||||||
|
* @param redirect - The redirect URL to validate (typically from query parameters)
|
||||||
|
* @param fallback - The fallback path to use if validation fails (default: '/dashboard')
|
||||||
|
* @returns A validated same-origin path or the fallback path
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* // Valid same-origin paths
|
||||||
|
* validateRedirect('/dashboard') // returns '/dashboard'
|
||||||
|
* validateRedirect('/projects/123') // returns '/projects/123'
|
||||||
|
*
|
||||||
|
* // Rejected external URLs (returns fallback)
|
||||||
|
* validateRedirect('https://evil.com') // returns '/dashboard'
|
||||||
|
* validateRedirect('//evil.com') // returns '/dashboard'
|
||||||
|
*
|
||||||
|
* // Invalid input (returns fallback)
|
||||||
|
* validateRedirect(null) // returns '/dashboard'
|
||||||
|
* validateRedirect(undefined) // returns '/dashboard'
|
||||||
|
*
|
||||||
|
* // Custom fallback
|
||||||
|
* validateRedirect('https://evil.com', '/login') // returns '/login'
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export const validateRedirect = (redirect: string | unknown, fallback = '/dashboard'): string => {
|
export const validateRedirect = (redirect: string | unknown, fallback = '/dashboard'): string => {
|
||||||
if (typeof redirect !== 'string') {
|
if (typeof redirect !== 'string') {
|
||||||
return fallback;
|
return fallback;
|
||||||
|
|||||||
Reference in New Issue
Block a user