API keys & authentication
The LinkMe platform supports two auth surfaces:
- Portal user authentication (email/password + social login)
- API authentication (app/server keys for SDK and automation calls)
Use this page as the canonical reference for auth behavior, setup, and troubleshooting.
Portal user authentication
Portal sign-in supports:
- Email/password
- Google OAuth
- GitHub OAuth
Account linking behavior
Account linking is currently based on normalized email (trim + lowercase).
- If social login returns an email that already exists, LinkMe reuses that existing user.
- If no user exists for that email, LinkMe creates a new account.
- A single user can therefore use email/password and social login if the email matches.
Verification behavior
- Email/password registration sends verification email (unless invite claim flow applies).
- OAuth-created users are marked verified during callback.
OAuth configuration
Google OAuth
Required server env:
GOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRET
Callback URL:
https://<your-auth-domain>/api/auth/google/callback
GitHub OAuth
Required server env:
GH_OAUTH_CLIENT_IDGH_OAUTH_CLIENT_SECRET
Runtime fallback is supported for legacy local envs:
GITHUB_CLIENT_IDGITHUB_CLIENT_SECRET
Callback URL:
https://<your-auth-domain>/api/auth/github/callback
If you use GitHub Actions secrets, do not start names with GITHUB_ (reserved prefix).
API key authentication (Edge + tooling)
The Edge API trusts signed requests from LinkMe app credentials managed in Portal.
API access is available on paid plans. On Free, requests return paid_plan_required with an upgrade URL.
Key types
| Key type | Use case | Capabilities |
|---|---|---|
| App API Key | Used by SDK/runtime resolve and claim flows for a specific app. | can_read by default; optional can_write for controlled automation. |
| Server/API Key | Used by backend jobs and scripts for create/update workflows. | Typically can_write; store server-side only. |
Each key stores:
appIdappKey(secret)- capability flags (
can_read,can_write) - optional label/expiry metadata
Sending credentials
SDK-style requests:
GET /api/deeplink?cid=abc123 HTTP/1.1
Host: li-nk.me
x-app-id: YOUR_APP_ID
x-api-key: YOUR_APP_KEY
Write/admin automation:
curl https://li-nk.me/api/links \
-H 'Authorization: Bearer sk_live_...' \
-H 'Content-Type: application/json' \
-d '{"slug":"spring","ios_store_url":"https://apps.apple.com/..."}'
Rotation & security hygiene
- Name keys by environment and owner (for example
prod-marketing-worker). - Never ship write-scoped keys in mobile clients.
- Rotate keys by adding new, deploying, then revoking old.
- Audit key usage and remove idle credentials.
Common OAuth errors
The redirect_uri is not associated with this application
Your OAuth app callback URL does not exactly match what LinkMe sends.
Example for production root-domain auth:
- auth page:
https://li-nk.me/auth - callback:
https://li-nk.me/api/auth/github/callback
Missing GH_OAUTH_CLIENT_ID/GH_OAUTH_CLIENT_SECRET
Deployment did not load GitHub OAuth secrets into the Portal env.
Verify secrets and deploy workflow env passthrough.