BeeL
Get StartedVeriFactuStripeAPI Reference

OAuth2

Authenticate via OAuth2 for MCP clients and third-party applications


BeeL. supports OAuth2 authorization_code with PKCE for third-party applications and MCP clients. Users log in on BeeL., consent the requested scopes, and your app receives a JWT access token.

Discovery

The OAuth2 Authorization Server publishes its configuration automatically:

GET https://app.beel.es/.well-known/oauth-authorization-server

Any standard OAuth2 client library can auto-configure from this URL.

Endpoints

EndpointURL
Authorizehttps://app.beel.es/oauth2/authorize
Tokenhttps://app.beel.es/oauth2/token
JWKShttps://app.beel.es/oauth2/jwks
Revokehttps://app.beel.es/oauth2/revoke

Client Registration

OAuth2 client registration is currently manual. Contact us at it@beel.es with:

  • Your application name
  • Your redirect_uri

We'll provide a client_id and client_secret. Authentication method: client_secret_basic.

Tokens

TokenFormatTTL
Access tokenJWT (RS256)1 hour
Refresh tokenOpaque30 days

The JWT access token contains:

ClaimDescription
subUser UUID
user_idUser UUID (same as sub)
scopeGranted scopes (array)
environmentPRODUCTION or SANDBOX
issIssuer URL
exp / iatExpiration and issued-at timestamps

Access tokens are validatable offline via the JWKS endpoint (RSA public key).

Authorization Code Flow with PKCE

Step 1: Generate PKCE Challenge

PKCE (S256) is required for all authorization requests.

# Generate code_verifier (random 43-128 chars)
CODE_VERIFIER=$(openssl rand -base64 32 | tr -d '=/+' | head -c 43)

# Generate code_challenge (SHA256 + base64url)
CODE_CHALLENGE=$(echo -n "$CODE_VERIFIER" \
  | openssl dgst -sha256 -binary \
  | base64 | tr '+/' '-_' | tr -d '=')

Step 2: Redirect User to Authorize

GET https://app.beel.es/oauth2/authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https://your-app.com/callback
  &scope=invoices:read customers:read
  &code_challenge=CODE_CHALLENGE
  &code_challenge_method=S256

The user logs in on BeeL. and is redirected to your redirect_uri with a code parameter.

Step 3: Exchange Code for Token

curl -X POST https://app.beel.es/oauth2/token \
  -d "grant_type=authorization_code" \
  -d "code=AUTHORIZATION_CODE" \
  -d "redirect_uri=https://your-app.com/callback" \
  -d "code_verifier=CODE_VERIFIER" \
  -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET"

Response:

{
  "access_token": "eyJraWQi...",
  "refresh_token": "abc123...",
  "token_type": "Bearer",
  "expires_in": 3599,
  "scope": "invoices:read customers:read"
}

Step 4: Use Access Token

curl https://app.beel.es/api/v1/invoices \
  -H "Authorization: Bearer ACCESS_TOKEN"

Step 5: Refresh Token

Access tokens expire after 1 hour. Use the refresh token to get a new one:

curl -X POST https://app.beel.es/oauth2/token \
  -d "grant_type=refresh_token" \
  -d "refresh_token=REFRESH_TOKEN" \
  -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET"

Refresh tokens are single-use. Each refresh returns a new refresh token. The previous one is invalidated.

Scopes

Request only the scopes your application needs. See Available Scopes for the full list.

scope=invoices:read customers:read products:read

If your token doesn't have the required scope for an endpoint, the API returns 403 Forbidden.

Environments

By default, OAuth2 tokens operate in the production environment. To use sandbox, include the sandbox scope in your authorization request:

scope=invoices:read customers:read sandbox

The environment is embedded in the JWT as the environment claim (PRODUCTION or SANDBOX). No additional headers are needed — the token itself determines the environment.

Scope includes sandbox?EnvironmentEffect
NoProductionReal invoices, AEAT submissions via VeriFactu
YesSandboxTest data, no AEAT submissions, no quota consumed

Unlike API keys (which use prefixes like beel_sk_test_), OAuth2 tokens determine the environment via the sandbox scope at authorization time.

Rate Limits

OAuth2 token requests are rate-limited like any other endpoint — see Rate limits.

Security Notes

  • PKCE (code_challenge_method=S256) is required
  • All communication must use HTTPS
  • Revoke tokens on user logout via the revocation endpoint
  • Store client_secret securely — never expose in client-side code
  • Access tokens are short-lived (1h) — use refresh tokens for long sessions