@tradly/auth
Version:
Auth package for Tradly - handles authentication (email, phone, social login)
825 lines (613 loc) • 18.9 kB
Markdown
Authentication package for Tradly platform - handles email, phone, and social
login with automatic PK key and auth key management.
```bash
npm install @tradly/auth
```
```typescript
import { initializeAuth, emailLogin } from "@tradly/auth";
// Initialize the package with your domain and environment
initializeAuth("beauty.tradly.co", "production");
// Now you can use all auth functions
const response = await emailLogin("user@example.com", "password123");
if (response.status) {
console.log("Login successful!", response.data);
}
```
**Important:** You must call `initializeAuth()` before using any other
functions. This sets up the domain, environment, and base URL for all API calls.
**Automatic Features on Initialization:**
- ✅ **UUID Auto-Generation** - Automatically generates and stores UUID in
cookie/localStorage
- ✅ **PK Key Auto-Fetch** - Automatically fetches and caches PK key from API
- ✅ **PK Key Encryption** - PK key is stored encrypted in cookie for security
```typescript
import { initializeAuth } from "@tradly/auth";
// Initialize with domain and environment
// This automatically:
// 1. Generates UUID (if not exists)
// 2. Fetches PK key from API
// 3. Stores PK key encrypted in cookie
// 4. Caches everything for fast access
initializeAuth("beauty.tradly.co", "production");
// Or with custom base URL
initializeAuth("beauty.tradly.co", "production", "https://api.custom.com");
```
- `production` - Uses `https://api.tradly.app` (default)
- `development` - Uses `https://api.dev.tradly.app`
- `local` - Uses `http://localhost:3000`
The package supports multiple domains in the same browser session. Each domain
maintains its own configuration, auth keys, and PK keys.
```typescript
// Initialize first domain
initializeAuth("beauty.tradly.co", "production");
// Switch to another domain
initializeAuth("fashion.tradly.co", "production");
// Get config for specific domain
import { getAuthConfigByDomain } from "@tradly/auth";
const config = getAuthConfigByDomain("beauty.tradly.co");
```
```typescript
import { emailLogin } from "@tradly/auth";
const response = await emailLogin("user@example.com", "password123");
if (response.status) {
const { user } = response.data;
// Auth keys are automatically stored in cookies/localStorage
console.log("User:", user);
} else {
console.error("Login failed:", response.error);
}
```
```typescript
import { phoneLogin } from "@tradly/auth";
const response = await phoneLogin(
"1234567890", // phone number
"+1", // country code
"password123" // password
);
if (response.status) {
console.log("Login successful!", response.data);
}
```
```typescript
import { socialLogin } from "@tradly/auth";
// Google login
const googleResponse = await socialLogin("google", googleAccessToken);
// Facebook login
const facebookResponse = await socialLogin("facebook", facebookAccessToken);
// Note:
// Currently the SDK types support "google" and "facebook" as providers.
// Apple login can be added when backend and SDK support are aligned.
```
```typescript
import { emailSignUp } from "@tradly/auth";
const response = await emailSignUp(
"John", // first name
"Doe", // last name
"user@example.com", // email
"password123" // password
);
if (response.status) {
console.log("Sign up successful!", response.data);
}
```
```typescript
import { phoneSignUp } from "@tradly/auth";
const response = await phoneSignUp(
"John", // first name
"Doe", // last name
"1234567890", // phone number
"+1", // country code
"password123" // password
);
if (response.status) {
console.log("Sign up successful!", response.data);
}
```
```typescript
import { verifyUser } from "@tradly/auth";
const response = await verifyUser(
verifyId, // Verification ID from sign up response
"123456" // OTP code
);
if (response.status) {
console.log("Verification successful!", response.data.user);
}
```
```typescript
import { resendOTP } from "@tradly/auth";
const response = await resendOTP({
verify_id: verifyId,
// ... other user data
});
if (response.status) {
console.log("OTP resent successfully!");
}
```
```typescript
import { getUserProfile } from "@tradly/auth";
const response = await getUserProfile();
if (response.status) {
const user = response.data;
console.log("User profile:", user);
}
```
```typescript
import { updateUserProfile } from "@tradly/auth";
const response = await updateUserProfile({
first_name: "John",
last_name: "Doe",
phone: "1234567890",
country_code: "+1",
// ... other fields
});
if (response.status) {
console.log("Profile updated!", response.data);
}
```
```typescript
import { getUserInfo } from "@tradly/auth";
// Get a specific user by ID
const response = await getUserInfo(123);
if (response.status) {
console.log("User info:", response.data);
}
```
The package automatically manages auth keys using domain-scoped cookies and
localStorage.
```typescript
import { getAuthKey, getUUID, getRefreshKey } from "@tradly/auth";
// Get current auth key (automatically reads from cookies/localStorage)
const authKey = getAuthKey();
// Get UUID
const uuid = getUUID();
// Get refresh key
const refreshKey = getRefreshKey();
```
```typescript
import { setAuthKey, setUUID } from "@tradly/auth";
// Set auth key (stores in cookies and localStorage)
setAuthKey("your-auth-key");
// Set UUID
setUUID("your-uuid");
```
```typescript
import { logout, quickLogout } from "@tradly/auth";
// Full logout - calls logout API and clears all data
const response = await logout();
if (response.status) {
console.log("Logout successful:", response.data?.message);
}
// Logout with UUID clearing (optional)
await logout({ clearUUID: true });
// Quick logout - clears all data without API call (client-side only)
quickLogout(); // Keeps UUID
quickLogout(true); // Also clears UUID
```
**What `logout()` clears:**
- ✅ Auth key (from cache, cookie, localStorage)
- ✅ Refresh key (from cache, cookie, localStorage)
- ✅ Firebase token (from cache, cookie, localStorage)
- ✅ User info (from cache, localStorage)
- ✅ PK key cache
- ✅ Optionally UUID (default: keeps UUID for future logins)
**Note:** The logout function always clears local data even if the API call
fails, ensuring users are logged out locally.
### Clear Auth Key (Manual)
```typescript
import { clearAuthKey, clearAllUserData } from "@tradly/auth";
// Clear only auth key
clearAuthKey();
// Clear all user data (auth_key, refresh_key, firebase_token, user_info)
clearAllUserData();
```
```typescript
import { hasAuthKey, hasUUID } from "@tradly/auth";
if (hasAuthKey()) {
console.log("User is authenticated");
}
if (hasUUID()) {
console.log("UUID is set");
}
```
When you call `initializeAuth()`, the PK key is automatically fetched and:
- ✅ Cached in memory (1 hour TTL)
- ✅ Stored encrypted in cookie (1 hour TTL)
- ✅ Available immediately for all API calls
**Security:** PK keys are encrypted using domain-based encryption before storing
in cookies.
### Get PK Key by Domain
```typescript
import { getPKKeyByDomain } from "@tradly/auth";
// Get PK key (checks cache first, then encrypted cookie, then API)
// Automatically stores encrypted in cookie after fetch
const pkData = await getPKKeyByDomain("beauty.tradly.co", "production");
if (pkData) {
const pkKey = pkData.key;
console.log("PK Key:", pkKey);
console.log("Domain Info:", pkData.domain);
}
```
**Note:** PK key is automatically fetched during `initializeAuth()`, so you
rarely need to call this manually.
```typescript
import { getCachedPKKey } from "@tradly/auth";
// Get PK key from cache (no API call)
const cachedPkKey = getCachedPKKey("beauty.tradly.co", "production");
if (cachedPkKey) {
console.log("Cached PK Key:", cachedPkKey.key);
}
```
```typescript
import { clearPKKeyCache } from "@tradly/auth";
// Clear cached PK key
clearPKKeyCache("beauty.tradly.co", "production");
```
```typescript
import { getAuthType } from "@tradly/auth";
// Get auth type configuration
const authType = await getAuthType();
// authType can be:
// - 1: Email only
// - 2: Phone only
// - 3: Both email and phone
// - null: Not configured
```
```typescript
import { isEmailAuthEnabled, isPhoneAuthEnabled } from "@tradly/auth";
// Check if email auth is enabled
const emailEnabled = await isEmailAuthEnabled();
// Check if phone auth is enabled
const phoneEnabled = await isPhoneAuthEnabled();
```
```typescript
import {
getAuthConfig,
getDomain,
getEnv,
getBaseUrl,
isAuthInitialized,
} from "@tradly/auth";
// Get full config
const config = getAuthConfig();
console.log(config); // { domain, env, baseUrl }
// Get individual values
const domain = getDomain();
const env = getEnv();
const baseUrl = getBaseUrl();
// Check if initialized
if (isAuthInitialized()) {
console.log("Auth package is initialized");
}
```
```typescript
import { clearAuthConfig, clearAuthConfigByDomain } from "@tradly/auth";
// Clear current domain config
clearAuthConfig();
// Clear specific domain config
clearAuthConfigByDomain("beauty.tradly.co");
```
For custom implementations (e.g., Next.js server-side with cookies-next):
```typescript
import { setAuthKeySource } from "@tradly/auth";
import { getCookie } from "cookies-next";
setAuthKeySource({
getAuthKey: () => {
// Custom implementation
return getCookie(`${domain}_auth_key`, { req, res });
},
getUUID: () => {
return getCookie(`${domain}_uuid`, { req, res });
},
getDomain: () => {
return req.headers.host || window.location.host;
},
});
```
The package provides low-level fetch utilities that automatically handle PK keys
and auth keys:
```typescript
import { get, post, put, del } from "@tradly/auth";
// GET request (automatically includes auth key or PK key)
const response = await get("/v1/users/me");
// POST request
const response = await post("/v1/users", {
name: "John Doe",
});
// PUT request
const response = await put("/v1/users/123", {
name: "Jane Doe",
});
// DELETE request
const response = await del("/v1/users/123");
```
- ✅ **Automatic PK Key Management** - Fetches and caches PK keys automatically
on initialization
- ✅ **PK Key Encryption** - PK keys are encrypted (hash-based) before storing
in cookies
- ✅ **Automatic UUID Generation** - Generates and stores UUID automatically on
initialization
- ✅ **Automatic Auth Key Management** - Stores and retrieves auth keys from
cookies/localStorage
- ✅ **Domain-Scoped Configuration** - Supports multiple domains in the same
session
- ✅ **Email Authentication** - Login and sign up with email
- ✅ **Phone Authentication** - Login and sign up with phone
- ✅ **Social Authentication** - Google, Facebook, Apple login
- ✅ **OTP Verification** - Verify and resend OTP codes
- ✅ **User Profile Management** - Get, update user profile
- ✅ **Auth Type Validation** - Check which auth methods are enabled
- ✅ **Complete Logout** - Calls logout API and clears all stored data
(auth_key, refresh_key, firebase_token, user_info, PK key cache)
- ✅ **TypeScript Support** - Full TypeScript definitions
- ✅ **Zero Configuration** - Works out of the box with automatic
cookie/localStorage handling
- ✅ **Server-Side Support** - Custom auth key source for SSR
- ✅ **Built-in Caching** - PK keys and responses are cached automatically
- ✅ **Secure Storage** - PK keys encrypted with domain-based hash algorithm for
cookie storage
## Testing
```bash
# Run all tests
npm run test:all
# Run integration tests (against real API)
npm run test:integration
# Run unit tests
npm run test:unit
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverage
# Run tests with UI
npm run test:ui
```
## TypeScript
Full TypeScript support with comprehensive type definitions:
```typescript
import type {
ApiResponse,
LoginResponse,
SignUpResponse,
UserProfile,
PKKeyResponse,
} from "@tradly/auth";
const response: ApiResponse<UserProfile> = await getUserProfile();
```
All API functions return a consistent response format:
```typescript
interface ApiResponse<T> {
status: boolean;
data: T;
error?: {
code: number;
message: string;
};
}
```
Example:
```typescript
const response = await emailLogin("user@example.com", "wrong-password");
if (!response.status) {
console.error("Error:", response.error?.message);
console.error("Code:", response.error?.code);
}
```
The package uses domain-scoped cookie naming:
- **Auth Key**: `${domain}_auth_key` (e.g., `beauty.tradly.co_auth_key`)
- **UUID**: `${domain}_uuid` (e.g., `beauty.tradly.co_uuid`)
- **Refresh Key**: `${domain}_refresh_key` (e.g.,
`beauty.tradly.co_refresh_key`)
- **PK Key**: `${domain}_pk_key_${env}` (e.g.,
`beauty.tradly.co_pk_key_production`) - **Encrypted**
**Security Note:** PK keys are encrypted using a domain-based hash algorithm
before storing in cookies. The encryption ensures that even if cookies are
accessed, the PK key cannot be easily extracted.
This ensures no conflicts when multiple Tradly applications run in the same
browser.
```typescript
import {
initializeAuth,
emailLogin,
getUserProfile,
logout,
} from "@tradly/auth";
// Initialize
initializeAuth("beauty.tradly.co", "production");
// Login
const loginResponse = await emailLogin("user@example.com", "password123");
if (loginResponse.status) {
// All keys and user info are automatically stored
console.log("Login successful!");
// Get user profile
const profileResponse = await getUserProfile();
if (profileResponse.status) {
console.log("User:", profileResponse.data);
}
// Logout (calls API and clears all data)
const logoutResponse = await logout();
if (logoutResponse.status) {
console.log("Logout successful!");
}
} else {
console.error("Login failed:", loginResponse.error);
}
```
```typescript
import {
initializeAuth,
emailSignUp,
verifyUser,
resendOTP,
} from "@tradly/auth";
initializeAuth("beauty.tradly.co", "production");
// Sign up
const signUpResponse = await emailSignUp(
"John",
"Doe",
"user@example.com",
"password123"
);
if (signUpResponse.status) {
const { verify_id } = signUpResponse.data;
// Verify OTP
const verifyResponse = await verifyUser(verify_id, "123456");
if (verifyResponse.status) {
console.log("Account verified!");
} else {
// Resend OTP if needed
await resendOTP({ verify_id });
}
}
```
For Next.js projects, see the [Next.js Integration Guide](./NEXTJS.md) for
detailed setup instructions.
The SDK supports both **server-only** usage and **hybrid (server + client)**
usage:
Use this when:
- All auth-dependent logic runs on the server (server components, route
handlers, server actions).
- You read cookies on the server and pass data down to client components as
props.
In this case you **do not need any client-side initialization** component.
```typescript
// app/layout.tsx (Server Component)
import { initializeAuth, setAuthKeySource } from "@tradly/auth";
import { cookies } from "next/headers";
const DOMAIN = "beauty.tradly.co";
// Initialize on server side (for server components)
initializeAuth(DOMAIN, "production");
// Set up cookie reading for server components
setAuthKeySource({
getAuthKey: () => {
const cookieStore = cookies();
return cookieStore.get(`${DOMAIN}_auth_key`)?.value || null;
},
getUUID: () => {
const cookieStore = cookies();
return cookieStore.get(`${DOMAIN}_uuid`)?.value || null;
},
getDomain: () => DOMAIN,
});
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html>
<body>{children}</body>
</html>
);
}
```
In this setup:
- `initializeAuth` configures domain/env/base URL.
- `setAuthKeySource` tells the SDK how to read `auth_key`/`uuid` from Next.js
server cookies.
- Server components can safely call `emailLogin`, `getUserProfile`, etc. without
any client initializer.
Use this when:
- You have client components that need to call SDK methods directly in the
browser (e.g. login forms, sign-up forms, profile pages).
- You want the SDK to create and manage cookies in the browser (UUID, auth key,
refresh key, PK key).
In this case you should still initialize on the server **and** add the
client-side `<AuthClientInit />` helper:
```typescript
// app/layout.tsx (Server Component)
import { initializeAuth, setAuthKeySource } from "@tradly/auth";
import { cookies } from "next/headers";
import { AuthClientInit } from "@tradly/auth/examples/nextjs-client-init";
const DOMAIN = "beauty.tradly.co";
// Initialize on server side (for server components)
initializeAuth(DOMAIN, "production");
// Set up cookie reading for server components
setAuthKeySource({
getAuthKey: () => {
const cookieStore = cookies();
return cookieStore.get(`${DOMAIN}_auth_key`)?.value || null;
},
getUUID: () => {
const cookieStore = cookies();
return cookieStore.get(`${DOMAIN}_uuid`)?.value || null;
},
getDomain: () => DOMAIN,
});
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html>
<body>
{/* Client-side initialization - ensures UUID & PK key are created
and kept in sync in the browser */}
<AuthClientInit
domain={DOMAIN}
env="production"
/>
{children}
</body>
</html>
);
}
```
Here:
- Server components can still use the SDK via `setAuthKeySource`.
- Client components can also call SDK functions (like `emailLogin`) and rely on
browser APIs (cookies, localStorage).
✅ **Server-side only** – just `initializeAuth` + `setAuthKeySource`
✅ **Server + client** – `initializeAuth` + `setAuthKeySource` +
`AuthClientInit`
✅ **Works in Server Components** – via `setAuthKeySource`
✅ **Works in Client Components** – via browser-based initialization
## License
ISC
## Repository
https://github.com/TRADLY-PLATFORM