Service accounts

Service accounts are administrative accounts specifically meant for API integrations. A service account is one of your organization’s administrators, but it is not tied to a specific person.

Why should I use service accounts? I currently use a regular administrator account for my API integration.

It is still possible to use a regular, personal account for an API integration. However, this means that all actions taken by this integration are effectively done by the person that is linked to this account. Using a service account is more transparent, because it clearly indicates that actions are being taken by a machine rather than a person.

There are several distinct benefits to using a service account for an API integration compared to using the credentials of a human administrator:

  • Continuity – API integrations are no longer reliant on a specific person, meaning that if an administrator leaves the organization, there is no impact on the technical connections.
  • Auditability – Actions performed by a service account are logged as such. No actions are taken by a human administrator without the user present.
  • Access control – The permissions and access available to the service account can be set to the minimum required levels.
  • Robustness – There are no interactive steps involved in obtaining a new access token, which is more suitable for an automated integration.

How can I set up a service account?

In order to set up a service account, you must be an administrator of your organization. In addition, you must also have the “Manage service accounts” permission. Please contact Drillster support if you require this permission.

To set up a new service account, navigate to the “Accounts” section in the Drillster console, and click the “plus” icon.

Add a service account

Next, select “Add service account…”. A service account only has a name — please choose something that is meaningful in the context of your organization. The account name may be shown to other users in various screens.

Create a service account

In the various user interfaces, service accounts are displayed with a small wrench icon badge attached to the avatar image to distinguish them from human administrators.

Assigning access and permissions

For all practical purposes, a service account is an administrator in your organization, just like any human administrators. This means that in order for a service account to be able to do anything meaningful in the organization (through API requests), the account must first be given the appropriate permissions and access.

After setting up a new service account, the account must be set up with the appropriate permissions, just like you would for any newly created human administrator. This is done by selecting the service account from the list of managed accounts. This will open the detail page of that service account, with the “Permissions” tab shown. Assign the appropriate permissions for the service account.

In many scenarios, service accounts will be used for group management. Service accounts do not have access to any groups by default – just like any other administrator group management access needs to be granted first. A service account may be set up as a group manager or viewer for specific groups, but it is also possible to make the service account a “Groups administrator”, meaning that the account becomes a manager or viewer of all groups in the organization.

How can a service account access the API?

To access the Drillster REST API, an OAuth access token is required. Drillster's OAuth documentation explains how a client application is registered with the Drillster platform, and how human users may use the authorization code flow to obtain an access token.

Service accounts must use the JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants as described in 🔗 RFC 7523. Once an OAuth access token is obtained, the API interactions are completely identical to other types of integrations.

The process of getting an access token works as follows:

  1. Create a JWT to request an access token for the service account user.
  2. Sign the JWT with a fixed and previously obtained private key.
  3. Use the signed JWT to obtain an access token at Drillster's token endpoint.

Access tokens created by this process have a limited validity period, and are not accompanied by a refresh token. Typically an API integration would generate a new access token for each operation or batch of operations. An access token may be requested as many times as needed. Instead of using refresh tokens the integration relies on a private key (which must be kept secret). The use of refresh tokens is not well suited for API integrations, as a single failed token refresh operation causes the integration to stop working.

⚠️ Caution

The private key must be kept secret under all circumstances. This means that a private key must never be used in a public client such as a web application or a mobile app. The use of this grant type is specifically designed for server-to-server API integrations.

Requirements

The following things are required in order to create a working API integration based upon service accounts:

  • Register a client application – All API requests are made by a client application. Please see the OAuth documentation for more information on how to do that. You will need the Client ID and Client secret for your integration.
  • Set up a service account – Please set up a service account as described above including the appropriate permissions and group access.
  • Create a key pair for the service account – Please see below for instructions.
  • Implement the code to create a signed token request and obtain access tokens – This is the least trivial part. Luckily there are many existing software libraries that can take care of this. Please see below for more information.

Generating a key pair

Access requests are signed by the customer with a private key. The key pair is generated by the Drillster platform, but Drillster only retains the public key. The private key is given to the user setting up the service account. It is the responsibility of that administrator to save the private key, and to ensure that it is kept secret.

In order to generate a key pair, go to the account detail screen in the Drillster console for the desired service account. Navigate to the “Keys” tab. Next, click the “plus” button and select “Generate new key” to create a new key pair.

Create a new key

This should result in the generation of a new key pair. The public key is stored in the Drillster system, and the private key is shown to the user. The private key is not stored anywhere on Drillster's systems. If desired it is also possible to supply your own public key. Please contact contact Drillster support for details.

Returned key

Keep in mind that this your only chance to view and download the private key. Please click on “Download JSON key file”. This should download the private key to your computer, wrapped in a small JSON file. You can also copy the private key itself, without metadata, to the clipboard by clicking the “copy” link. Please ensure that you have the key file in your possession before dismissing the popup.

The private key can be viewed of as the password for the service account. It is your responsibility to keep it secret and to keep it secure. Should the private key ever become compromised, be sure to delete the associated public key from the Drillster system by clicking the appropriate delete icon in the list of keys. Once the public key has been removed, the private key can no longer be used.

The downloaded JSON key file looks something like this:

{
  "keyId":"cf9f895ff1f64e2f9ceea45074f56c52",
  "privateKey":"-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAxIBAQCQbJx3YdmaXAtJ\nOvPHEZ1H2NZBgBHmcZDCjFFX2pDpG1WFgEIgxLiOKWehKNuqh7wFG3udXwCFqeRZ\nd8qu+ISe7/9XyWuyUagpLyYo+9c6S55lViZg7nPgQI1TrPlv5ApzIIgUNJFqe/jj\n1rAkdpgbudC112Z3cWikIl+kBbhexZwovp/hA3wJ1uvtZYkyFIfJwC6HZxVJSyYk\n73qS7Sb0RPM6K5zuvYKnb7KgeUOsVWdg/xo0WVwwVsHiHjBv7w+tcJU3yq753+MH\ndqfZe3lbmQpsBA4b+ov7wB1SN++v34mtceGvn9BX1xNQ+lq15iSCcxMZLDCmBVM2\nwCzfoWRNAgMBAAECggEAIef9y+FDDwQw+h5HASNXg3iaxIHmse1TiPkcV73Oa4up\nRlBYNg05Ltb1p1ZKS/zV3XUYTlfxbW/3VjHTecSKji3WCqwVBqY5DoItOU32t47q\n5eeV1wfkWG+PPmfLn8Mv2Nt4VxYIVbGJOyQ58jWNfGThZO+O9NfBM1eGkKFvKYBs\nkYoWKQDaf5ujGLpFrL5sOFM2tReXBR1Rfa0Oa8BhkQqke/D4qbzVVTPL+uOKicyL\nroWtERxGguvLW5HMGJYDhNTJh5GkkdTBk2aD9UIRq9cISxEX32Xj+1sNZvkvBIG7\n7Iz/I3L6XUEx0HF/SAuWWxbaDAcOYiRJxdd3SKIZWQKBgQDRAvApllm0SBe1b6br\nxGDnTjuSmDO55OeqbSiwDJv0dcbhH+OsS+by/2IYInJ/JFDT3rwYQRtRum8O+Aq4\nbTGNckiiBM0llvXLbm59CpMtbRlEpeypISEKJ47QF96h+eXaVZPqwL7PCFAINxxh\neGoT8wWYniwVw/LSN2+P7b17YwKBgQCw5IoVNFnKaUtdJysXXzD3H5VDgyUt24PA\nfCKRRlhuAMS5xpkxP4xE4ecuoU7a8A6Z6d0eycpGxZkxnEnZVu3kSMtmkIu6HNgh\n6TpcD90ZnkoxwYrqpTtaE01GZ9yua0GF15Gh3qNHhXGP2Vq70YUCcIbIiKApGxCK\nvs2uvxYojwKBgHirlpacDExOdwm0XY2vAjdo7nHzV6HSq4G0phIGJaAcw2bEL4ER\nDVRr52mBsdL/136LENN7+1bTKT1eLWpO+JXuTkrkNMCoCF6b8kRU76YBX95HYXw/\n+UBQmF5B+bJQgcjtMYoOH9uNtA8aKlOH3s6Ht0pmv5MNX0rI4KsbGhN7AoGAWYvX\nutQ9gBG9bPKfBb3Sc8cxMHP7JjOxhodQmGob6dPJwqGeeyfIQjZ5aUmPOZW8Tn3s\nyeEs3Ja67jpHyBYRZzbSgKE7moNvhfsi5+e/7XAL7xQi1pW+beLHg5SgSktRaAew\nWVjzHwmWa1OEcv+lbY65LFq9eRGSViowxP1GolECgYEAynb4EwAA4LkqIzYl2CRF\nAz8k7cU71Uusas2W3bKh8N2MsHelXD4yNFYsSTfxkmfmaGfbpaZ8pOFxIiQYWzeU\n5rc5VHzUBBzNZYfnjfJzI4zjXlEw2KYrudBTdRuQiDcgIupxUid/V+pS81sTvC2C\nCz8P0jVCGDa8f4ZiTB/Qb8o=\n-----END PRIVATE KEY-----",
  "keyAlgorithm":"RSA_2048",
  "serviceAccountId":"iqKpEF3URCe0yAsyrsk_4g"
}

Obtaining an access token

In order to obtain an access token using a service account, the JWT profile for authorization grants flow must be followed. This flow is different from the more common authorization code grant flow.

There are two steps to this process:

  1. Create a signed JWT request
  2. Exchange the JWT for an access token

An access token may be requested for the service account itself, or for an account that is managed by the organization to which the service account belongs.

Creating a signed JWT The creation of a signed JWT should be automated, ideally using existing, industry standard libraries. However, what follows is an explanation of how this can be done manually for illustrative purposes.

The ingredients of a JWT request are:

  • The signing algorithm. This can be gleaned from the JSON key file. The example key is created according to RSA_2048. This corresponds to a signing algorithm of RS256 in JWT speak.

  • The key ID. This value can also be taken from the JSON key file – it is listed as keyId.

  • The user ID of the service account. This too is listed in the JSON key file, as serviceAccountId.

  • (Optional) The target user ID for whom an access token is being requested. This flow may be used to request an access token for the service account itself, or for a user that is managed by the organization.

  • The URL of Drillster's token endpoint. This is the endpoint where the signed JWT can be exchanged for an access token. This endpoint is advertised at https://www.drillster.com/.well-known/oauth-authorization-server, under token_endpoint. The current location of the token endpoint is https://www.drillster.com/daas/oauth/token. The endpoint location is not likely to change, but if it does change it will be advertised in the above “well known” location.

  • An expiry timestamp. Each JWT request must have an expiry timestamp which is in the future, but not more than one hour. The format is seconds since the Unix epoch (i.e. since 1970-01-01 00:00:00 UTC). For the purpose of this example you can for example use the date +%s command on most Unix-based systems. Be sure to add some seconds to the value to place it into the future (but not more than an hour). You could for instance add 1800 to the value to give yourself 30 minutes to use your JWT. A typical timestamp looks something like this: 1607020363.

This example uses the 🔗 JTW.io website as a handy tool to manually construct, sign and check JWTs. Once you have assembled all the ingredients, please head over to JWT.io. A JWT consists of a header, a payload (also known as the Claims Set) and a signature. In our case the JWT header is constructed as follows:

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "cf9f895ff1f64e2f9ceea45074f56c52"
}

The fields are:

  • alg – the algorithm
  • typ – always equal to JWT
  • kid – the key ID

The payload (Claims Set) is constructed as follows:

{
  "sub": "iqKpEF3URCe0yAsyrsk_4g",
  "iss": "iqKpEF3URCe0yAsyrsk_4g",
  "aud": "https://www.drillster.com/daas/oauth/token",
  "exp": 1607020363
}

The fields are:

  • sub – The user ID for whom an access token is requested, i.e. either the service account ID itself, or an account ID of an account managed by the organization that the service account is part of. Note that for human users the sub claim may also be populated with an email address or a third party ID. For service accounts, the user ID may be found in the JSON key file.
  • iss – The user ID of the service account, i.e. the issuer of the JWT.
  • aud – The URI of the token endpoint.
  • exp – The expiry timestamp

Fill in the header and payload into the designated input boxes on JWT.io.

Finally the JWT needs to be signed with the private key. In the JWT.io utility this can be done by pasting the private key into the “private key” box of the signature section. This should generate a signed JWT on the left hand side of the screen. You can also paste in the public key to verify the key pair, but this is not necessary to create a signed JWT.

If all went according to plan you now have a valid, signed JWT that can be used to obtain an OAuth access token (if used within the expiry period).

Requesting the access token

Exchanging a signed JWT for an access token is simply a matter of offering it to the token endpoint. The format is as follows:

POST https://www.drillster.com/daas/oauth/token
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
client_id=874a16d4ac764ce4a545f0cca4584c63
client_secret=5782b2e7532b48b5a0798f2ad6644614
assertion=eyJhbGciOi…ZmQ4NjFiZT.eyJzdWIiOi…YwNzAxNTM2.SLdboQsTud…dMLYvI75sA

The parameters are:

  • grant_type – always equal to urn:ietf:params:oauth:grant-type:jwt-bearer
  • client_id – the client ID for your registered client application
  • client_secret – the client secret for your registered client application
  • assertion – the signed JWT

A successful response typically looks like this:

{
  "access_token":"eyJhbGciOiJSUzI1NiIsInR5cI6IkpXVCJ9.eyJzdWIiOiJO1NNNUQ0VlQ2dWZpcENMWkh0V0FRIiwiZXhwIjoxNjA3MDE1MzczLCJqdGkiOIwNGI4MWIyNy0wOGU2LTQzMjQtOTU4Ni1lMGMzYmZhNWMzMWEiLCJjbGllbnRfaWQiOiI3YTMwMzAzYWRhN2M0MWZlOThmZDFlMmY0OTY2YTA4NSIsInNjb3BlIjpbIlJPTEVfVVNFUiJdfQ.SrzNkXIlR9XHUy5QGAsod4wD7l1n2uUG0UmyyHaSFf0E4qOiGItdOn-riU__kNgWAfrGHEytxML6Fry3G901sCfF3dNTXRGcNDi28P_sCEynR2VKBeEPZxxIq47-nhLyMQwvl3TWaesQxrUDNQf3gMxh8bGtjLhai8Ov4lPdKvnGw9Y9kE12vyLCZVPHePnlLea3_2LWIln484ql3JChHgi8JeQj_Wr_1pFmXqznTZ6e5UCnP7WL4p4tsTsGlw1IGdCiQ3XuM6Lu3r0N8gWVfaefScJyppZRwvhx_7WfeUaOBSbE1ntW_IcE3ADE2a1hENKDj2b3VhEHmdHeDk7yQ",
  "token_type":"bearer",
  "expires_in":3599,
  "scope":"ROLE_USER",
  "jti":"04b81b27-08e6-4324-9586-e0c3bfa5c31a"
}

Simply pick up the value for access_token and use it as a bearer token in your API requests. Once the access token expires it cannot be refreshed – a new token must be requested again. A new access token may be requested at any time, before or after expiry of the current token.