Authentication
The Bikeep API supports three authentication methods, each designed for different integration scenarios. Choose the one that fits your use case.
Choosing an Auth Method
| Method | Best For | Session Tracking | Payment Support | Complexity |
|---|---|---|---|---|
| S2S OAuth2 | Backend integrations, IoT management | No | No | Low |
| External Users | Mobile apps, user-facing products | Yes | Yes | Medium |
| Public Access | Map displays, availability widgets | N/A | N/A | None |
Decision guide
- “I want to control hardware from my backend” → S2S OAuth2
- “I want to build a mobile app where users park and pay” → External Users
- “I just want to show availability on a map” → Public Access
S2S OAuth2 (Service-to-Service)
The simplest method. Your backend authenticates directly with Bikeep using client credentials.
How it works
sequenceDiagram
participant Server as Your Server
participant Auth as Bikeep Auth
participant API as Bikeep API
Server->>Auth: POST /oauth2/token
(client_id + client_secret)
Auth-->>Server: access_token (1h TTL)
Server->>API: GET /location/v1/...
Authorization: Bearer token
API-->>Server: JSON response
Get a token
curl -X POST https://auth.bikeep.com/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
Alternative: Pass credentials as Basic Auth:
curl -X POST https://auth.bikeep.com/oauth2/token \
-H "Authorization: Basic BASE64(client_id:client_secret)" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials"
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600
}
Token usage
Include the token in every API request:
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Tokens expire after 1 hour. Request a new token before expiry — there is no refresh token in the S2S flow.
Limitations
S2S OAuth2 does not create user identities, so:
- No session tracking — device sessions will not be associated with users
- No payment processing — usage fees cannot be charged
- No user statistics — usage history is not available
If you need these features, use External Users.
External Users (3rd Party Apps)
For mobile apps and user-facing products that need full session tracking, payments, and statistics. This method involves a handshake between your backend and Bikeep to verify user identities.
How it works
sequenceDiagram
participant App as Your App
participant Server as Your Server
participant API as Bikeep API
Note over App,API: Sign-up
App->>Server: sign up
Server->>API: POST /sign-up
(user_id, operator_id)
API->>Server: POST to your sign-up endpoint
{user_id, bikeep_user_id}
Server-->>API: 200 OK
API-->>Server: 204 No Content
Server-->>App: store bikeep_user_id
Note over App,API: Sign-in
App->>Server: sign in
Server->>API: POST /sign-in
(bikeep_user_id, operator_id,
challenge_token)
API->>Server: POST to your sign-in endpoint
{user_id, challenge_token}
Server-->>API: {bikeep_user_id}
Note right of API: Bikeep verifies match
API-->>Server: access_token + refresh_token
Server-->>App: ready
App->>API: API calls with Bearer token
Prerequisites
You must implement two verification endpoints on your server that Bikeep will call:
1. Sign-up verification endpoint
Bikeep POSTs to this endpoint when a user first registers:
// POST to your endpoint
{
"user_id": "your-internal-user-id",
"bikeep_user_id": "bikeep-uuid-for-this-user"
}
Your endpoint must store the user_id → bikeep_user_id mapping — you will need the bikeep_user_id for all subsequent sign-in and API calls.
Respond with any 2xx status to confirm.
Status codes: Bikeep treats
< 400as success,4xxas rejection (ERRORS.OPERATOR_REJECTION), and5xxas an error (ERRORS.OPERATOR_ERROR).
2. Sign-in verification endpoint
Bikeep POSTs to this endpoint on every sign-in attempt. The payload includes the challenge_token — the same value your app originally sent to /sign-in:
// POST to your endpoint
{
"user_id": "your-internal-user-id",
"challenge_token": "the-nonce-your-app-sent-to-sign-in"
}
Your endpoint must validate the challenge_token — confirm it matches a recently generated nonce for this user. This proves the sign-in was initiated by your app (see How the challenge_token works below).
If valid, respond with the bikeep_user_id:
{
"bikeep_user_id": "bikeep-uuid-for-this-user"
}
Bikeep verifies that this bikeep_user_id matches the one sent in the original /sign-in request. If it does not match, the sign-in is rejected.
If the challenge token is invalid, respond with 4xx to reject the sign-in.
Status codes: Bikeep treats
< 400as success (proceeds to matchbikeep_user_id),4xxas rejection (sign-in denied), and5xxas an error.
Timeout: Both verification endpoints must respond within 5 seconds. If your endpoint does not respond in time, the request fails with
504and error codeERRORS.SERVICE_TIMED_OUT.
How the challenge_token works
The challenge_token is a short-lived nonce that proves a sign-in request was initiated by your app — not by a third party who happens to know a bikeep_user_id.
The round-trip:
- Your app generates a unique, short-lived token (nonce) for this sign-in attempt
- Your app sends it to Bikeep via
POST /sign-inalong with thebikeep_user_id - Bikeep forwards it to your sign-in verification endpoint — Bikeep never inspects the content, it only requires the field to be non-empty
- Your server validates the token, proving the request originated from your app
sequenceDiagram
participant App as Your App
participant Server as Your Server
participant Bikeep
App->>Server: (1) generate nonce
Server->>Bikeep: (2) POST /sign-in
{bikeep_user_id, challenge_token}
Bikeep->>Server: (3) POST callback
{user_id, challenge_token}
Server->>Server: (4) validate nonce
Server-->>Bikeep: {bikeep_user_id}
Bikeep-->>Server: access_token
Server-->>App: ready
Security: Without a valid
challenge_token, anyone who knows abikeep_user_idcould sign in as that user. Always generate a cryptographically random nonce, store it server-side with a short TTL (e.g., 60 seconds), and reject any token your server did not recently issue.
Sign up a user
curl -X POST https://services.bikeep.com/external-users-auth/v1/sign-up \
-H "Content-Type: application/json" \
-d '{
"user_id": "your-internal-user-id",
"operator_id": "your-operator-uuid"
}'
Partial failure recovery: If sign-up succeeds on Bikeep’s side but your verification endpoint fails (returns 4xx/5xx or times out), the API returns an error — but the user already exists in Bikeep’s system. To recover:
- Retry the sign-up. Bikeep handles duplicates automatically — your verification endpoint will be called again with the
user_idandbikeep_user_id, giving you another chance to store the mapping.- If you already have the
bikeep_user_id, skip straight to sign-in. The sign-in verification callback includes theuser_id, so you can re-establish the mapping at that point.
Sign in a user
curl -X POST https://services.bikeep.com/external-users-auth/v1/sign-in \
-H "Content-Type: application/json" \
-d '{
"bikeep_user_id": "bikeep-uuid-for-this-user",
"operator_id": "your-operator-uuid",
"challenge_token": "your-app-generated-nonce"
}'
| Field | Description |
|---|---|
bikeep_user_id |
The Bikeep UUID you received during sign-up (stored in your user_id → bikeep_user_id mapping) |
operator_id |
Your operator UUID (provided by Bikeep) |
challenge_token |
A short-lived nonce your app generated for this sign-in attempt — Bikeep forwards it to your verification endpoint for validation |
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "eyJhbGciOiJSUzI1NiIs..."
}
Refresh a token
curl -X POST https://services.bikeep.com/external-users-auth/v1/refresh \
-H "Content-Type: application/json" \
-d '{
"bikeep_user_id": "bikeep-uuid-for-this-user",
"refresh_token": "eyJhbGciOiJSUzI1NiIs..."
}'
operator_idis also accepted but optional (for debugging only). Onlybikeep_user_idandrefresh_tokenare required.
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIs..."
}
Access tokens expire after 1 hour. Use the refresh token to get a new access token without requiring the user to sign in again. The refresh endpoint returns only a new access_token — the original refresh_token remains valid and should be reused for subsequent refreshes.
Error reference
All error responses follow this format:
{
"error_code": "ERRORS.EXAMPLE_ERROR",
"error_message": "human-readable description",
"status_code": 400
}
Sign-up errors
| Error Code | HTTP Status | Cause |
|---|---|---|
ERRORS.MISSING_OPERATOR_ID |
400 | operator_id is empty |
ERRORS.MISSING_USER_ID |
400 | user_id is empty |
ERRORS.FAILED_TO_SIGN_UP |
400 | Sign-up failed |
ERRORS.OPERATOR_REJECTION |
400 | Your sign-up verification endpoint returned 4xx |
ERRORS.OPERATOR_ERROR |
500 | Your sign-up verification endpoint returned 5xx |
ERRORS.SERVICE_TIMED_OUT |
504 | Your verification endpoint did not respond within 5 seconds |
Sign-in errors
| Error Code | HTTP Status | Cause |
|---|---|---|
ERRORS.INVALID_OPERATOR_ID |
400 | operator_id is not a valid UUID |
ERRORS.INVALID_BIKEEP_USER_ID |
400 | bikeep_user_id is not a valid UUID |
ERRORS.INVALID_CHALLENGE_TOKEN |
400 | challenge_token is empty |
ERRORS.FAILED_TO_SIGN_IN |
400 | Sign-in failed — user not found, verification rejected, or bikeep_user_id mismatch |
ERRORS.SERVICE_TIMED_OUT |
504 | Your verification endpoint did not respond within 5 seconds |
Refresh errors
| Error Code | HTTP Status | Cause |
|---|---|---|
ERRORS.INVALID_REFRESH_TOKEN |
400 | refresh_token is empty or too short |
ERRORS.AUTHENTICATION_FAILED |
400 | Refresh token is expired, revoked, or user not found |
ERRORS.SERVICE_TIMED_OUT |
504 | Request timed out |
Public Access
No authentication required. Only one endpoint is publicly accessible:
curl https://services.bikeep.com/location/v1/public-areas/{public_area_id}/locations
This returns location data in GeoJSON format including availability counts. Use it for public-facing maps and availability displays.
See the Availability Display guide for integration examples.
Note: The
public_area_idis provided by Bikeep and defines a geographic region (e.g., a city or campus) whose locations are publicly visible.
Environment URLs
| Service | URL |
|---|---|
| Auth | https://auth.bikeep.com |
| API | https://services.bikeep.com |