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_idbikeep_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 < 400 as success, 4xx as rejection (ERRORS.OPERATOR_REJECTION), and 5xx as 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 < 400 as success (proceeds to match bikeep_user_id), 4xx as rejection (sign-in denied), and 5xx as an error.

Timeout: Both verification endpoints must respond within 5 seconds. If your endpoint does not respond in time, the request fails with 504 and error code ERRORS.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:

  1. Your app generates a unique, short-lived token (nonce) for this sign-in attempt
  2. Your app sends it to Bikeep via POST /sign-in along with the bikeep_user_id
  3. Bikeep forwards it to your sign-in verification endpoint — Bikeep never inspects the content, it only requires the field to be non-empty
  4. 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 a bikeep_user_id could 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:

  1. Retry the sign-up. Bikeep handles duplicates automatically — your verification endpoint will be called again with the user_id and bikeep_user_id, giving you another chance to store the mapping.
  2. If you already have the bikeep_user_id, skip straight to sign-in. The sign-in verification callback includes the user_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_idbikeep_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_id is also accepted but optional (for debugging only). Only bikeep_user_id and refresh_token are 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_id is 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