Set up a long-lived offline token for a service account using the Keycloak REST API. Keycloak implements the OpenID Connect protocol, so this is a standard procedure for any OpenID Connect server.
Refer to Offline Access in the official Keycloak documentation for more information.
CLIENT_SECRET variable has been set up.
my-test-client value in the command below with the ID of the target client.scope option should be set to offline_access.Get a long-lived token for a service account with the following command:
ncn-mw# curl -s -d grant_type=client_credentials -d client_id="my-test-client" -d client_secret="${CLIENT_SECRET}" -d scope=offline_access \
            https://api-gw-service-nmn.local/keycloak/realms/shasta/protocol/openid-connect/token | jq
Example output:
{
  "access_token": "longAsciiStringTruncated",
  "expires_in": 31536000,
  "refresh_expires_in": 0,
  "refresh_token": "anotherLongAsciiStringTruncated",
  "token_type": "bearer",
  "not-before-policy": 0,
  "session_state": "80a96e21-0942-447e-b1d7-21da55d3ff4a",
  "scope": "profile offline_access email"
}
Two things are important in the returned response compared to when requesting an “online” token:
refresh_expires_in value is 0. The refresh token will not expire and become invalid by itself. The refresh tokens can be revoked via administrative action in Keycloak.refresh_token value can be used to get a fresh token any time and will be needed if the access token expires (which will happen in 31,536,000 seconds after the access token was issued).my-test-client value in the command below with the ID of the target client.REFRESH_TOKEN value with the string returned in the previous section.grant_type option is set to refresh_token.Refresh a long-lived token for a service account with the following command:
ncn-mw# curl -s -d grant_type=refresh_token -d client_id="my-test-client" -d client_secret="${CLIENT_SECRET}" -d refresh_token="REFRESH_TOKEN" \
            https://api-gw-service-nmn.local/keycloak/realms/shasta/protocol/openid-connect/token | jq
Example output:
{
  "access_token": "longAsciiStringTruncated",
  "expires_in": 31536000,
  "refresh_expires_in": 0,
  "refresh_token": "anotherLongAsciiStringTruncated",
  "token_type": "bearer",
  "not-before-policy": 0,
  "session_state": "80a96e21-0942-447e-b1d7-21da55d3ff4a",
  "scope": "profile offline_access email"
}