JouloDocs

OAuth2

Build third-party applications that access Joulo data on behalf of users

If you're building an application that accesses Joulo data on behalf of other users, use OAuth2 with PKCE (Proof Key for Code Exchange) to obtain scoped access tokens.

OAuth2 is for third-party applications. If you only need to access your own data, use a personal API token instead.

Overview

Joulo implements the OAuth2 Authorization Code flow with PKCE:

  1. Your app redirects the user to Joulo to authorize access
  2. The user approves the requested scopes
  3. Joulo redirects back with an authorization code
  4. Your app exchanges the code for an access token and refresh token

Scopes

Request only the scopes your application needs:

ScopeAccess
chargers:readGET /chargers — charger status and active sessions
chargers:writePOST /chargers — register new chargers
sessions:readGET /sessions — charging session history
energy:readGET /energy — energy statistics and aggregates

Authorization flow

Step 1: Authorize

Send a POST request to the authorization endpoint with the user's Supabase JWT:

POST https://<project>.supabase.co/functions/v1/oauth-authorize

Request body (JSON):

FieldRequiredDescription
client_idYesYour OAuth client ID
redirect_uriYesMust match a registered redirect URI for your client
response_typeYesMust be code
scopeYesSpace-separated list of scopes (e.g. chargers:read sessions:read)
stateYesRandom string to prevent CSRF — verify it matches on callback
code_challengeYesBase64url-encoded SHA-256 hash of the code_verifier
code_challenge_methodYesMust be S256

The response contains a redirect_url with the authorization code and state parameters.

Step 2: Exchange the code for tokens

POST https://<project>.supabase.co/functions/v1/oauth-token

Request body (JSON or form-encoded):

FieldRequiredDescription
grant_typeYesMust be authorization_code
client_idYesYour OAuth client ID
client_secretYesYour OAuth client secret
codeYesThe authorization code received in step 1
redirect_uriYesMust match the URI used in step 1
code_verifierYesThe original PKCE code verifier

Response:

{
  "access_token": "a1b2c3d4e5f6...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "f6e5d4c3b2a1...",
  "scope": "chargers:read sessions:read"
}

Step 3: Use the access token

Include the access token in the Authorization header when calling the Joulo API:

curl https://api.joulo.nl/functions/v1/api/chargers \
  -H "Authorization: Bearer ACCESS_TOKEN"

Step 4: Refresh the token

Access tokens expire after 1 hour. Use the refresh token to obtain a new pair:

POST https://<project>.supabase.co/functions/v1/oauth-token
FieldRequiredDescription
grant_typeYesMust be refresh_token
client_idYesYour OAuth client ID
client_secretYesYour OAuth client secret
refresh_tokenYesThe refresh token from the previous token response

Refresh tokens expire after 30 days and are rotated on each use — the old refresh token is revoked when a new one is issued.

Token revocation

To revoke an access or refresh token:

POST https://<project>.supabase.co/functions/v1/oauth-revoke
FieldRequiredDescription
tokenYesThe access or refresh token to revoke
client_idYesYour OAuth client ID
client_secretYesYour OAuth client secret

Security requirements

  • PKCE with S256 is required for all authorization requests
  • Authorization codes expire after 10 minutes and can only be used once
  • Redirect URIs must be pre-registered on your OAuth client
  • All token endpoints use no-store cache headers

Store client secrets and refresh tokens securely. Never expose them in client-side code or public repositories.