Vacation Tracker Docs
OAuth2 Authorization

Legacy flow (deprecated)

The original Vacation Tracker OAuth2 hostname at api.app.vacationtracker.io. Kept as a permanent compatibility mapping for existing integrations. New integrations should use auth.vacationtracker.io.

Deprecated hostname. This page documents api.app.vacationtracker.io/oauth/*, the original host. It's kept as a permanent compatibility mapping so existing integrations (notably Zapier) keep working without changes. New integrations should use the modern flow at auth.vacationtracker.io. It's the same API surface, supports both public and confidential clients, and adds PKCE, Dynamic Client Registration, and metadata discovery. Nothing about new integrations requires this hostname.

Overview

  • Grant type: Authorization Code (confidential clients only)
  • Token format: JWT (issued by AWS Cognito)
  • Token lifetime: access tokens expire after 60 minutes, refresh tokens after 365 days
  • Authorization codes: single-use, expire after 10 minutes
  • PKCE: not supported. Security relies on client secrets, the state parameter, and redirect URI validation.

Base URL

All legacy endpoints are served under the /oauth path on the original API host:

https://api.app.vacationtracker.io/oauth

This host is kept alive indefinitely as a compatibility mapping onto the same underlying API. It serves the same routes as the modern base URL (https://auth.vacationtracker.io), so your existing Zapier and confidential-client integrations do not need to migrate.

Flow diagram

Step 1: Redirect to authorization endpoint

Redirect the user's browser to the authorization endpoint with the required parameters:

GET https://api.app.vacationtracker.io/oauth/authorize
  ?client_id=your-client-id
  &redirect_uri=https://yourapp.com/callback
  &state=random-csrf-token
  &scope=openid email profile
  &response_type=code
ParameterRequiredDescription
client_idYesYour registered OAuth client ID
redirect_uriYesMust exactly match a registered redirect URI for your client
stateYesRandom string for CSRF protection. You must verify this value when the user returns
scopeNoSpace-separated list of scopes. Defaults to openid
response_typeNoMust be code. Defaults to code

Step 2: User authenticates

The authorization endpoint validates your parameters and redirects the user to Vacation Tracker's login page. The user can authenticate via:

  • Microsoft account
  • Google account
  • Slack account
  • Email and password

Step 3: User grants permission

After authentication, the user sees a consent screen showing your application's name and the requested scopes. They can approve or deny the request.

Step 4: Receive authorization code

If the user approves, Vacation Tracker redirects back to your redirect_uri with an authorization code and your state value:

https://yourapp.com/callback?code=a1b2c3d4-e5f6-7890-abcd-ef1234567890&state=random-csrf-token

Important:

  • Verify that the state parameter matches what you sent in Step 1
  • The authorization code is single-use and expires after 10 minutes

Step 5: Exchange code for tokens

Make a server-side POST request to exchange the authorization code for tokens:

curl -X POST https://api.app.vacationtracker.io/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=a1b2c3d4-..." \
  -d "redirect_uri=https://yourapp.com/callback" \
  -d "client_id=your-client-id" \
  -d "client_secret=your-client-secret"

Or using HTTP Basic authentication:

curl -X POST https://api.app.vacationtracker.io/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -u "your-client-id:your-client-secret" \
  -d "grant_type=authorization_code" \
  -d "code=a1b2c3d4-..." \
  -d "redirect_uri=https://yourapp.com/callback"

Step 6: Receive tokens

On success, you receive a JSON response with your tokens:

{
  "access_token": "eyJ...",
  "id_token": "eyJ...",
  "refresh_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 3600
}
  • access_token: use this to authenticate API requests. Expires in 60 minutes.
  • id_token: contains user identity claims. Expires in 60 minutes.
  • refresh_token: use this to get new access tokens. Valid for 365 days.

Step 7: Use the access token

Include the access token in the Authorization header when calling protected endpoints:

curl https://api.app.vacationtracker.io/oauth/me \
  -H "Authorization: Bearer eyJ..."

Refreshing tokens

When the access token expires, use the refresh token to get a new one:

curl -X POST https://api.app.vacationtracker.io/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=eyJ..." \
  -d "client_id=your-client-id" \
  -d "client_secret=your-client-secret"

Response:

{
  "access_token": "eyJ...",
  "refresh_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 3600
}

The same refresh token is returned. Vacation Tracker does not rotate refresh tokens.

Error handling

If something goes wrong, the authorization endpoint returns an error as a JSON response:

{
  "error": "invalid_client",
  "error_description": "Unknown client_id"
}

See Endpoints for the complete list of error codes per endpoint.

On this page