My App

Authentication & Authorization

JWT tokens, OAuth2 flows, M2M credentials, token refresh, and multi-tenancy context.

Every API call (except health checks and incoming webhooks) requires a JWT Bearer token. The token carries your identity, tenant context, and role — the API uses it to enforce access control and data isolation.

Your App  →  OAuth2 Server  →  JWT  →  KSeF API Gateway (validates)

Base URLs

EnvironmentAuth ServerAPI
Demohttps://demo-auth.ksefapi.comhttps://demo.ksefapi.com
Productionhttps://auth.ksefapi.comhttps://gateway.ksefapi.com

Machine-to-machine authentication. No user interaction required. Best for ERP systems, automated pipelines, and API integrations.

curl -X POST https://demo-auth.ksefapi.com/realms/ksef-realm/protocol/openid-connect/token \
  -d 'client_id=YOUR_CLIENT_ID' \
  -d 'client_secret=YOUR_CLIENT_SECRET' \
  -d 'grant_type=client_credentials'
ParameterTypeRequiredDescription
client_idstring✅M2M client ID
client_secretstring✅M2M client secret
grant_typestring✅Must be client_credentials

Response (200):

{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 300
}

Client credentials grant does not return a refresh_token. When the token expires (300s = 5 min), request a new one with the same call.


User Login — Password Grant

For user-facing applications where you collect username and password.

POST /api/auth/login
Content-Type: application/json

Request:

{
  "email": "[email protected]",
  "password": "SecurePassword123!"
}

Response (200):

{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 300,
  "refresh_token": "eyJhbGciOiJIUzI1NiIs...",
  "refresh_expires_in": 1800
}
FieldDescription
access_tokenJWT for API calls (5 min TTL)
refresh_tokenUse to get new access_token without re-login (30 min TTL)
expires_inAccess token lifetime in seconds
refresh_expires_inRefresh token lifetime in seconds

User Login — Browser Redirect (OAuth2 Authorization Code)

For web applications using the OAuth2 login page.

# Get auth URLs
curl https://demo.ksefapi.com/api/auth/urls
{
  "login_url": "https://demo-auth.ksefapi.com/realms/ksef-realm/protocol/openid-connect/auth?...",
  "register_url": "https://demo-auth.ksefapi.com/realms/ksef-realm/protocol/openid-connect/registrations?...",
  "login_redirect": "/api/auth/login-url",
  "register_redirect": "/api/auth/register-url"
}

Flow:

  1. Redirect user to login_url
  2. User authenticates on the OAuth2 login page
  3. User is redirected back to your redirect_uri with an authorization code
  4. Exchange the code for tokens via the callback endpoint

Token Refresh

curl -X POST https://demo.ksefapi.com/api/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{"refresh_token": "eyJhbGciOiJIUzI1NiIs..."}'

Response (200):

{
  "access_token": "eyJhbGciOiJSUzI1NiIs...(new)",
  "token_type": "Bearer",
  "expires_in": 300,
  "refresh_token": "eyJhbGciOiJIUzI1NiIs...(new)",
  "refresh_expires_in": 1800
}

Both tokens are rotated on refresh. Always store and use the latest refresh token.


Current User Info

curl -H "Authorization: Bearer $TOKEN" \
  https://demo.ksefapi.com/api/auth/me

Response (200):

{
  "sub": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "email": "[email protected]",
  "name": "Jan Kowalski",
  "realm_access": {
    "roles": ["user"]
  },
  "company_associations": [
    {
      "company_id": "22919080-f3fe-4aff-8d71-f6493afc956a",
      "company_name": "BIZNETO SP. Z O.O.",
      "nip": "8133793363",
      "role": "admin"
    }
  ]
}

Using the Token

Include the token in every API request:

curl -H "Authorization: Bearer $TOKEN" \
  https://demo.ksefapi.com/api/companies

Common errors:

StatusErrorCause
401Token has expiredToken older than 5 min — refresh or re-authenticate
401Invalid tokenMalformed or tampered JWT
403Insufficient permissionsYour role doesn't allow this operation
403Company access deniedToken not associated with the requested company

Token Lifecycle Best Practices

  1. Cache tokens — don't request a new token for every API call
  2. Refresh proactively — refresh when ~80% of TTL has elapsed (at ~4 min for a 5-min token)
  3. Handle 401 gracefully — catch expired token errors, refresh, and retry the request
  4. For M2M — simply request a new token when needed (no refresh token available)
  5. Store securely — never log or expose tokens in URLs or client-side storage

Authentication Endpoints Summary

MethodEndpointDescription
POST/realms/ksef-realm/protocol/openid-connect/tokenGet token (M2M or password)
POST/api/auth/loginUser login (password grant)
POST/api/auth/refreshRefresh token
GET/api/auth/meCurrent user info
GET/api/auth/urlsOAuth2 redirect URLs
GET/api/auth/login-urlRedirect to OAuth2 login
GET/api/auth/register-urlRedirect to registration
GET/api/auth/callbackOAuth2 callback handler
POST/api/auth/logoutInvalidate session

On this page