Skip to main content

Overview

The Macondo Link Manager API uses a combination of Google OAuth 2.0 for login and JWT (JSON Web Tokens) for session management. Authentication is cookie-based, providing secure, stateless authentication.

Authentication Flow

1. Google OAuth Login

Users authenticate via Google OAuth 2.0:
  1. Redirect user to /auth/google
  2. User authorizes with Google
  3. Google redirects to /auth/google/callback
  4. API validates user and sets JWT cookie
  5. User is redirected to frontend

Authentication Methods

Google OAuth 2.0

Only users with email addresses from the allowed domain can authenticate. Domain restrictions are enforced server-side.

Initiate Login

Redirect users to:
GET /auth/google
This endpoint initiates the OAuth flow and redirects to Google’s authorization page.

OAuth Callback

GET /auth/google/callback
Google redirects here after user authorization. This endpoint:
  1. Exchanges authorization code for access token
  2. Fetches user profile from Google
  3. Validates user email domain
  4. Creates or updates user in database
  5. Generates JWT token
  6. Sets secure cookie
  7. Redirects to frontend
OAuth Scopes Requested:
  • email: Access to user’s email address
  • profile: Access to basic profile information (name, picture)
User Information Retrieved:
{
  "email": "[email protected]",
  "name": "John Doe",
  "picture": "https://lh3.googleusercontent.com/a/..."
}

JWT Token

After successful Google authentication, a JWT is generated and stored in a secure cookie. Cookie Name: macondo.token Token Payload:
{
  "sub": "550e8400-e29b-41d4-a716-446655440000",
  "name": "John Doe",
  "email": "[email protected]",
  "avatarUrl": "https://lh3.googleusercontent.com/a/...",
  "exp": 1705843200,
  "iat": 1705238400
}
Token Properties:
  • Expiration: 7 days
  • Algorithm: HS256 (default for @fastify/jwt)
  • Storage: HTTP-only cookie
  • Path: /
  • SameSite: none (cross-origin support)
  • Secure: true (HTTPS only)
{
  cookieName: "macondo.token",
  path: "/",
  maxAge: 60 * 60 * 24 * 7, // 7 days
  httpOnly: true,
  sameSite: "none",
  secure: true
}
The JWT is stored in an HTTP-only cookie, making it inaccessible to JavaScript. This prevents XSS attacks but requires the frontend to be served from a trusted domain.

Protected Routes

Most API endpoints require authentication via the authHook middleware.

Authentication Hook

The authHook validates the JWT token on every protected request: Location: /home/daytona/workspace/source/api/src/hooks/auth.ts:5 Process:
  1. Extract macondo.token cookie from request
  2. Verify JWT signature and expiration
  3. Decode token payload
  4. Attach user data to request.user
  5. Allow request to proceed
Protected Resources:
  • All /links endpoints
  • All /clients endpoints
  • All /campaigns endpoints
  • All /dashboard endpoints
  • /me endpoint

Making Authenticated Requests

Include the JWT cookie in all requests to protected endpoints:
curl https://li.mcd.ppg.br/me \
  -H "Cookie: macondo.token=YOUR_JWT_TOKEN"
Using fetch (JavaScript):
fetch('https://li.mcd.ppg.br/me', {
  credentials: 'include' // Important: includes cookies
})
Using axios (JavaScript):
axios.get('https://li.mcd.ppg.br/me', {
  withCredentials: true // Important: includes cookies
})

Authentication Errors

Missing Token

Status: 401 Unauthorized
{
  "message": "Token de autenticação não fornecido."
}
This occurs when no macondo.token cookie is present in the request.

Invalid or Expired Token

Status: 401 Unauthorized
{
  "message": "Token inválido ou expirado."
}
This occurs when:
  • Token signature is invalid
  • Token has expired (> 7 days old)
  • Token format is malformed

Domain Not Allowed

During login, if the user’s email domain is not allowed: Redirect: Frontend with error parameter
https://frontend.example.com/?error=DOMAIN_NOT_ALLOWED
Only users from authorized email domains can access the API.

Get Current User

Retrieve information about the authenticated user:
GET /me
Authentication: Required

Response (200)

{
  "user": {
    "sub": "550e8400-e29b-41d4-a716-446655440000",
    "name": "John Doe",
    "email": "[email protected]",
    "avatarUrl": "https://lh3.googleusercontent.com/a/...",
    "exp": 1705843200,
    "iat": 1705238400
  }
}

Example

curl https://li.mcd.ppg.br/me \
  -H "Cookie: macondo.token=YOUR_JWT_TOKEN"

Logout

Log out by clearing the authentication cookie:
POST /auth/logout
Authentication: Not required (but cookie will be cleared if present)

Response (200)

{
  "code": "LOGOUT_SUCCESS",
  "message": "Logout realizado com sucesso."
}

Example

curl -X POST https://li.mcd.ppg.br/auth/logout \
  -H "Cookie: macondo.token=YOUR_JWT_TOKEN"
Frontend logout flow:
// 1. Call logout endpoint
await fetch('https://li.mcd.ppg.br/auth/logout', {
  method: 'POST',
  credentials: 'include'
});

// 2. Redirect to login page
window.location.href = '/login';

Security Best Practices

Never expose JWT tokens in URLs or logs. Tokens should only be transmitted via secure HTTP-only cookies.

Token Security

  • HTTP-Only: Tokens are not accessible via JavaScript
  • Secure Flag: Tokens only transmitted over HTTPS
  • SameSite: Cross-origin protection
  • Short Expiration: Tokens expire after 7 days
  • Server-Side Validation: All tokens verified on every request

Domain Restrictions

The API enforces email domain restrictions during OAuth login. If a user with an unauthorized domain attempts to log in, they will be redirected with an error. Error handling in frontend:
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('error') === 'DOMAIN_NOT_ALLOWED') {
  alert('Your email domain is not authorized to access this application.');
}

CORS and Credentials

  • Origin: Restricted to configured frontend URL
  • Credentials: Must be included in all cross-origin requests
  • Methods: Limited to GET, POST, PUT, DELETE, OPTIONS

Environment Configuration

Required environment variables:
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
JWT_SECRET=your_strong_secret_key
FRONTEND_URL=https://your-frontend.com
BASE_URL=https://li.mcd.ppg.br
The JWT_SECRET should be a strong, randomly generated string. Never commit this value to version control.

Troubleshooting

Token Not Sent with Request

Problem: Requests to protected endpoints fail with 401 error Solutions:
  • Ensure credentials: 'include' (fetch) or withCredentials: true (axios)
  • Check that cookie is set after successful login
  • Verify CORS configuration allows credentials
  • Confirm frontend and API URLs match CORS settings

Token Expires Too Quickly

Problem: Users are logged out unexpectedly Solution: Tokens expire after 7 days. Implement a “keep me logged in” flow or prompt users to re-authenticate when tokens expire. Problem: Cookie not set in cross-origin scenarios Solutions:
  • Ensure API uses sameSite: 'none' and secure: true
  • Verify both frontend and API use HTTPS
  • Check browser settings allow third-party cookies
  • Confirm FRONTEND_URL environment variable matches actual frontend URL

Next Steps

Create Links

Start creating shortened links

Manage Clients

Organize your agency clients

View Analytics

Track link performance

User Profile

Access user information

Build docs developers (and LLMs) love