Auth
Auth Endpoints
Section titled “Auth Endpoints”Authentication endpoints handle the OAuth 2.0 login flow with WorkOS AuthKit.
Initiate Login
Section titled “Initiate Login”POST /api/v1/auth/login
Starts the OAuth login flow and returns the authorization URL.
Authentication
Section titled “Authentication”None required.
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
returnTo | string | No | URL to redirect to after login (default: /) |
curl -X POST https://app.bitmarks.sh/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{"returnTo": "/dashboard"}'const response = await fetch('https://app.bitmarks.sh/api/v1/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ returnTo: '/dashboard' })});const { authorizationUrl } = await response.json();window.location.href = authorizationUrl;Response
Section titled “Response”Status: 200 OK
{ "authorizationUrl": "https://authkit.workos.com/sso/authorize?client_id=..."}Error Response
Section titled “Error Response”Status: 500 Internal Server Error
{ "error": "Failed to initiate login"}OAuth Callback
Section titled “OAuth Callback”GET /api/v1/auth/callback
Handles the OAuth callback from WorkOS after user authentication.
Authentication
Section titled “Authentication”None required.
Query Parameters
Section titled “Query Parameters”| Param | Type | Required | Description |
|---|---|---|---|
code | string | Yes | Authorization code from WorkOS |
state | string | No | Return URL (default: /) |
Behavior
Section titled “Behavior”- Exchanges authorization code for tokens with WorkOS
- Creates user in database if first login
- Sets session cookies
- Redirects to return URL
Response
Section titled “Response”Status: 302 Found
Redirects to the URL specified in state parameter.
Headers:
Set-Cookie: bitmarks_session=TOKEN; HttpOnly; Secure; SameSite=Lax; Max-Age=604800Set-Cookie: bitmarks_refresh=TOKEN; HttpOnly; Secure; SameSite=Lax; Max-Age=2592000Location: /dashboardError Handling
Section titled “Error Handling”On error, redirects to /login?error=<message>
Logout
Section titled “Logout”POST /api/v1/auth/logout
Clears session cookies and ends the user session.
Authentication
Section titled “Authentication”None required (clears any existing session).
curl -X POST https://app.bitmarks.sh/api/v1/auth/logoutawait fetch('https://app.bitmarks.sh/api/v1/auth/logout', { method: 'POST', credentials: 'include'});Response
Section titled “Response”Status: 200 OK
{ "success": true}Both bitmarks_session and bitmarks_refresh cookies are cleared.
Error Response
Section titled “Error Response”Status: 500 Internal Server Error
{ "error": "Failed to logout"}Get Session
Section titled “Get Session”GET /api/v1/auth/session
Returns current session information.
Authentication
Section titled “Authentication”Cookie-based (checks session validity).
curl https://app.bitmarks.sh/api/v1/auth/session \ -b "bitmarks_session=YOUR_TOKEN"const response = await fetch('https://app.bitmarks.sh/api/v1/auth/session', { credentials: 'include'});const session = await response.json();Response (Authenticated)
Section titled “Response (Authenticated)”Status: 200 OK
{ "authenticated": true, "user": { "user_id": "user_01ABC123", "email": "user@example.com", "name": "John Doe", "avatar_url": "https://avatars.example.com/user.png", "email_verified": true }}Response (Not Authenticated)
Section titled “Response (Not Authenticated)”Status: 401 Unauthorized
{ "authenticated": false}User Object Fields
Section titled “User Object Fields”| Field | Type | Description |
|---|---|---|
user_id | string | Unique user identifier |
email | string | User’s email address |
name | string | User’s display name |
avatar_url | string | URL to user’s avatar image |
email_verified | boolean | Whether email is verified |
Refresh Token
Section titled “Refresh Token”POST /api/v1/auth/refresh
Uses the refresh token to obtain a new access token.
Authentication
Section titled “Authentication”Requires bitmarks_refresh cookie.
curl -X POST https://app.bitmarks.sh/api/v1/auth/refresh \ -b "bitmarks_refresh=YOUR_REFRESH_TOKEN"const response = await fetch('https://app.bitmarks.sh/api/v1/auth/refresh', { method: 'POST', credentials: 'include'});Response
Section titled “Response”Status: 200 OK
{ "success": true}A new bitmarks_session cookie is set automatically.
Error Responses
Section titled “Error Responses”Status: 401 Unauthorized
{ "error": "No refresh token"}or
{ "error": "Failed to refresh token"}Cookie Details
Section titled “Cookie Details”| Cookie | Duration | Purpose |
|---|---|---|
bitmarks_session | 7 days | Access token for API requests |
bitmarks_refresh | 30 days | Refresh token for obtaining new access tokens |
Cookie Attributes
Section titled “Cookie Attributes”HttpOnly- Not accessible via JavaScriptSecure- Only sent over HTTPS (production)SameSite=Lax- CSRF protectionDomain=.bitmarks.sh- Shared across subdomains (production)
Token Refresh Strategy
Section titled “Token Refresh Strategy”async function authenticatedFetch(url, options = {}) { let response = await fetch(url, { ...options, credentials: 'include' });
if (response.status === 401) { // Try to refresh the token const refreshResponse = await fetch('/api/v1/auth/refresh', { method: 'POST', credentials: 'include' });
if (refreshResponse.ok) { // Retry original request response = await fetch(url, { ...options, credentials: 'include' }); } else { // Redirect to login window.location.href = '/login'; throw new Error('Session expired'); } }
return response;}