End User Portal
The End User Portal provides a self-service experience for your customers. End users can register, log in, activate license keys, view their licenses, and verify licenses from your application loader.
How It Works
End users are scoped to an organization. Each organization can have its own portal, identified by its slug (e.g., your-company). End users register with their email and password, then link license keys to their account.
Portal Authentication
Register
const response = await fetch('https://api.geckoguard.com/v1/enduser/auth/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
orgSlug: 'your-company',
email: 'user@example.com',
password: 'securepassword123'
})
});
const { data } = await response.json();
// data.endUser = { id, email, createdAt }
// data.token = JWT session token
// data.org = { id, slug, name }
Login
const response = await fetch('https://api.geckoguard.com/v1/enduser/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
orgSlug: 'your-company',
email: 'user@example.com',
password: 'securepassword123'
})
});
Logout
POST /v1/enduser/auth/logout
Authorization: Bearer END_USER_SESSION_TOKEN
License Management
Activate (Link) a License
End users link a license key to their account:
await fetch('https://api.geckoguard.com/v1/enduser/licenses/activate', {
method: 'POST',
headers: {
'Authorization': 'Bearer END_USER_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
orgSlug: 'your-company',
licenseKey: 'LICENSE-KEY-123'
})
});
A license can only be linked to one end user account. If it's already linked to a different account, the request returns 409 ALREADY_CLAIMED.
List Licenses
const response = await fetch('https://api.geckoguard.com/v1/enduser/licenses', {
headers: { 'Authorization': 'Bearer END_USER_TOKEN' }
});
const { data } = await response.json();
// data.licenses = [{ licenseId, status, expiresAt, hwidBound, product: { id, name }, linkedAt }]
Get Profile
GET /v1/enduser/me
Authorization: Bearer END_USER_TOKEN
Returns the end user's profile and organization info.
Loader Authentication
For desktop/native application loaders, there's a dedicated auth flow that returns a loader token — a lightweight JWT for license verification:
Loader Login
const response = await fetch('https://api.geckoguard.com/v1/enduser/loader/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
orgSlug: 'your-company',
email: 'user@example.com',
password: 'securepassword123'
})
});
const { data } = await response.json();
// data.token = loader JWT token
// data.org = { id, slug, name }
Loader Verify
Verify a license from your application using the loader token. This endpoint resolves the product by the license key (no productId needed) and returns a signed response for tamper detection:
const response = await fetch('https://api.geckoguard.com/v1/enduser/verify', {
method: 'POST',
headers: {
'Authorization': 'Bearer LOADER_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
orgSlug: 'your-company',
licenseKey: 'LICENSE-KEY-123',
hwid: 'device-hardware-id',
meta: { // Optional
ip: '192.168.1.1',
userAgent: 'MyApp/2.0',
version: '2.0.0'
}
})
});
const { data } = await response.json();
// data.decision = { allow: true } or { allow: false, reason: 'HWID_MISMATCH' }
// data.licenseId, data.productId, data.expiresAt, data.hwid
// data.sig = cryptographic signature for tamper detection
// data.kid = signing key ID
Signed Responses
The loader verify endpoint returns a sig field — an Ed25519 signature of the response payload. Your application can verify this signature to detect response tampering (man-in-the-middle attacks):
// The response includes:
// - data: the payload (decision, licenseId, expiresAt, etc.)
// - sig: Ed25519 signature of the stable-stringified payload
// - kid: signing key ID for key rotation support
Decision Reasons
| Reason | Description |
|---|---|
NOT_FOUND | License key not found or doesn't belong to the org |
REVOKED | License is revoked or expired |
EXPIRED | License has passed its expiry date |
HWID_MISMATCH | Hardware ID doesn't match the bound device |
Custom Domains
Organizations can configure custom domains for their portal. The resolve endpoint maps hostnames to organizations:
GET /v1/enduser/orgs/resolve?hostname=portal.yourcompany.com
Rate Limiting
Portal endpoints are rate-limited per IP and per email:
| Action | Limit |
|---|---|
| Registration | 20/min per IP, 10/min per email |
| Login | 60/min per IP, 20/min per email |
| Loader login | 60/min per IP |
| Verify | Configurable per IP and per license |
Use Cases
- Customer self-service — let users manage their own licenses without contacting support
- Desktop app loaders — authenticate users and verify licenses with signed responses
- White-label portals — custom domains for a branded experience
- License activation — let users activate purchased license keys on their account