---
title: "Token endpoint"
method: POST
path: "/auth/realms/fhir/protocol/openid-connect/token"
tags: ["Authentication", "Bulk FHIR"]
---

# Token endpoint

`POST /auth/realms/fhir/protocol/openid-connect/token`

## Request

- Base URL: `https://sso.ema.md`
- URL: `https://sso.ema.md/auth/realms/fhir/protocol/openid-connect/token`
- Auth: none declared

Exchange an authorization `code` for tokens, refresh a token, or obtain a `client_credentials` token. The same endpoint serves both interactive apps and Bulk FHIR backend services — which fields you send depends entirely on your `grant_type`.

### authorization_code / refresh_token (interactive apps)

Send `client_id`/`client_secret` in the body (`client_secret_post`).

### client_credentials (Bulk FHIR / backend services)

No `client_secret` — authentication is `private_key_jwt` instead:

- Send `client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer` and a `client_assertion` JWT, signed with the private key matching the public JWKS your client is registered with.
- Assertion claims: `iss`/`sub` = your `client_id`, `aud` = this token endpoint URL, plus `jti`/`iat`/`exp` (a short expiry — 5 minutes is typical).
- Signing algorithm confirmed working: `ES384`.
- `scope` is required on this grant (space-separated `system/*.rs` scopes) — it's not implied the way it can be for the other two grants.

The schema below lists every field used across all three grants; see above for which combination applies to yours.

## Request body `application/x-www-form-urlencoded`

- object
  - `grant_type` string, required: `authorization_code`, `refresh_token`, or `client_credentials`
  - `code` string: Authorization code (authorization_code grant)
  - `redirect_uri` string: Must match the authorize request (authorization_code grant)
  - `code_verifier` string: PKCE code verifier (authorization_code grant)
  - `refresh_token` string: (refresh_token grant)
  - `client_id` string: authorization_code and refresh_token grants only — client_credentials identifies the client via the client_assertion JWT's iss/sub claims instead
  - `client_secret` string: authorization_code and refresh_token grants only — never sent on the client_credentials grant
  - `client_assertion_type` string: client_credentials grant only
  - `client_assertion` string: client_credentials grant only — a JWT signed with your private key, matching the public JWKS your client is registered with. See this endpoint's description for the required claims and confirmed signing algorithm.
  - `scope` string: Required on the client_credentials grant (space-separated system/*.rs scopes). Optional on the other two grants.

## Response `200`

Token response

- object
  - `access_token` string
  - `token_type` string
  - `expires_in` integer
  - `refresh_token` string: Present when offline_access is granted
  - `scope` string
  - `id_token` string: Present when the openid scope is requested

---

[API](https://skmtc.dev/modmed/apis/modmed-certified-api-authentication.md) - [All operations](https://skmtc.dev/modmed/apis/modmed-certified-api-authentication/llms.txt) - [OpenAPI document](https://skmtc.dev/modmed/apis/modmed-certified-api-authentication/revisions/0f71eaec4f98?raw)
