Management API Guide
The Morio Management API is a OpenAPI v3.1 compliant API, and the main user-facing API in Morio.
If you’re already familiar with the API, and are merely looking for answers on which endpoint to use or what data to expect, refer to /docs/reference/apis/api.
Purpose of Morio’s Management API
Morio’s Management API (the API) provides all functionality that you can access through the Morio user interface (UI).
This includes configuring Morio, as well as handling identity providers, enabling and disabling services, managing user accounts and API keys, generating certificates, and building client packages.
This API is Morio’s main user-facing API, and when we mention the API in the Morio documentation without being specific about which API it is, you can assume we are referring to this one.
Accessing the API
The API itself is available on all Morio nodes and can be accessed under the
prefix /-/api/
.
All documentation of API endpoints is relative to this prefix, so to access
the /status
endpoint of this API on a Morio node, you should use:
https://[your-server-name]/-/api/status
If your server’s DNS name
is example.morio.it
, you could run this curl command to get the /status
endpoint:
curl https://example.morio.it/-/api/status
Or, if your system does not trust the Morio certificates:
curl --insecure https://example.morio.it/-/api/status
Authentication
Grab a JSON Web Token from the /login
endpoint and
use it in subsequent API calls as your Bearer token. Pre-expiry, tokens can be
renewed at the /token
endpoint.
Identity Providers
The Morio Management API supports all authentication types that are supported by Morio for HTTP-based access. In practical terms, HTTP-based authentication in Morio is backed by an identity provider, of which there are currently four supported types:
- The
mrt
identity provider lets you authenticate via the Morio Root Token - The
apikey
identity provider lets you authenticate via an API Key - The
local
identity provider lets you authenticate via a Local Morio Account - The
ldap
identity provider lets you authenticate using an LDAP Account, including LDAP-compatible backends such as Active Directory
Logging In
Use the /login
endpoint to
exchange your credentials for a JSON Web Token (JWT). That
JWT can then be used in subsequent API calls to authenticate them.
The /login
endpoint documentation includes
examples for each identity providers listed above. The response from the API
will include a jwt
key that holds the JWT. Below is an example using the
local
identity provider:
{
"jwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibG9jYWwudGVzdEFjY291bnQxNzIyMjM2OTIyMDQ4Iiwicm9sZSI6InVzZXIiLCJhdmFpbGFibGVfcm9sZXMiOlsidXNlciJdLCJoaWdoZXN0X3JvbGUiOiJ1c2VyIiwicHJvdmlkZXIiOiJsb2NhbCIsIm5vZGUiOiIzOWIwYjVmZC02NjQ4LTQxZjgtYjNiOS1kZjk2YzVkMTE1NzkiLCJjbHVzdGVyIjoiODYwMjkwNmYtNTQzNy00Y2NlLWIxNTAtN2MzMzg3ZGEzNmZhIiwiaWF0IjoxNzIyMjM2OTIzLCJuYmYiOjE3MjIyMzY5MjMsImV4cCI6MTcyMjI1MTMyMywiYXVkIjoibW9yaW8iLCJpc3MiOiJtb3JpbyIsInN1YiI6Im1vcmlvIn0.sij21XpVw2i6SjTZtms9Sl4WsTYh6wgcr0c79x7-6OQPaWam-Ne8t_mzcI5Opa8qOjdFBDBoRHjairzyURpQ-p0BmrDANp4gw17lAqvmgGySwTC-T0yqdRpvZLV85ZhSps3XqiTuWObOVztd3MOLc6xbbp-SEIk6VimzDWcSQbInDfTCbbx4OivWjIcpA6XGfVcXWWtZiJz7y8E8E2jrckV3jkqRUZuhZ_HIcOyh1LSKb4WWWybCcu-D6hC1VipX_oy2Q8227V-VY1Kgryxe-F8xckgBkIoFjdejVsz4UpkvWXsYEJEZjgKLC0zZEZJVaEJC3w6QpNj-nc5d5dgF0TDq_6T0GvTaoN_UZGBgYioGTd0wXHpw0Trzc0VQrN5O3yBYjnhsbwSWlhHlClSAbV_CCy2qUAyDOrXBGmOlIYN8YZ_eJe-wIYioISd9dd0h5rbTSjtMqpX8fDoRZv0jFraVDOk0eMwiGM_TKhsFfR3sx0samCt7k3nCTseLeufCxRUkBZmeoG7o0NrZ0tbTrUoS9XJX_PDK3v9u-Z1LqjmJe7nERG55gXQer-_a5yWn-LKWooAYFW3iLwZEpvAxQF_VtW2xoCkrj5BD9UOnotj6emHmK76oURrSd3waQ_EWmnwf86dSXPQiljp41jHt95V7jyN5P4my-ogotTKxoGA",
"data": {
"user": "local.testAccount1722236922048",
"role": "user",
"available_roles": ["user"],
"highest_role": "user",
"provider": "local"
}
}
JSON Web Token
The value in the jwt
key of the response body holds our JSON Web Token (JWT).
It can be decoded to reveal its payload data:
{
"user": "local.testAccount1722236922048",
"role": "user",
"available_roles": ["user"],
"highest_role": "user",
"provider": "local",
"node": "39b0b5fd-6648-41f8-b3b9-df96c5d11579",
"cluster": "8602906f-5437-4cce-b150-7c3387da36fa",
"iat": 1722236923,
"nbf": 1722236923,
"exp": 1722251323,
"aud": "morio",
"iss": "morio",
"sub": "morio"
}
Bearer Authentication
Now that you have your JWT, it serves as your Bearer Token and you can use
Bearer Authentication in subsequent API requests. To do so, pass the content
of the JWT as the Authorization
header, prefixed by Bearer
.
A JSON representation of the headers would look like this:
{
"Authorization": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibG9jYWwudGVzdEFjY291bnQxNzIyMjM2OTIyMDQ4Iiwicm9sZSI6InVzZXIiLCJhdmFpbGFibGVfcm9sZXMiOlsidXNlciJdLCJoaWdoZXN0X3JvbGUiOiJ1c2VyIiwicHJvdmlkZXIiOiJsb2NhbCIsIm5vZGUiOiIzOWIwYjVmZC02NjQ4LTQxZjgtYjNiOS1kZjk2YzVkMTE1NzkiLCJjbHVzdGVyIjoiODYwMjkwNmYtNTQzNy00Y2NlLWIxNTAtN2MzMzg3ZGEzNmZhIiwiaWF0IjoxNzIyMjM2OTIzLCJuYmYiOjE3MjIyMzY5MjMsImV4cCI6MTcyMjI1MTMyMywiYXVkIjoibW9yaW8iLCJpc3MiOiJtb3JpbyIsInN1YiI6Im1vcmlvIn0.sij21XpVw2i6SjTZtms9Sl4WsTYh6wgcr0c79x7-6OQPaWam-Ne8t_mzcI5Opa8qOjdFBDBoRHjairzyURpQ-p0BmrDANp4gw17lAqvmgGySwTC-T0yqdRpvZLV85ZhSps3XqiTuWObOVztd3MOLc6xbbp-SEIk6VimzDWcSQbInDfTCbbx4OivWjIcpA6XGfVcXWWtZiJz7y8E8E2jrckV3jkqRUZuhZ_HIcOyh1LSKb4WWWybCcu-D6hC1VipX_oy2Q8227V-VY1Kgryxe-F8xckgBkIoFjdejVsz4UpkvWXsYEJEZjgKLC0zZEZJVaEJC3w6QpNj-nc5d5dgF0TDq_6T0GvTaoN_UZGBgYioGTd0wXHpw0Trzc0VQrN5O3yBYjnhsbwSWlhHlClSAbV_CCy2qUAyDOrXBGmOlIYN8YZ_eJe-wIYioISd9dd0h5rbTSjtMqpX8fDoRZv0jFraVDOk0eMwiGM_TKhsFfR3sx0samCt7k3nCTseLeufCxRUkBZmeoG7o0NrZ0tbTrUoS9XJX_PDK3v9u-Z1LqjmJe7nERG55gXQer-_a5yWn-LKWooAYFW3iLwZEpvAxQF_VtW2xoCkrj5BD9UOnotj6emHmK76oURrSd3waQ_EWmnwf86dSXPQiljp41jHt95V7jyN5P4my-ogotTKxoGA"
}
To do so in curl, use this syntax:
curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibG9jYWwudGVzdEFjY291bnQxNzIyMjM2OTIyMDQ4Iiwicm9sZSI6InVzZXIiLCJhdmFpbGFibGVfcm9sZXMiOlsidXNlciJdLCJoaWdoZXN0X3JvbGUiOiJ1c2VyIiwicHJvdmlkZXIiOiJsb2NhbCIsIm5vZGUiOiIzOWIwYjVmZC02NjQ4LTQxZjgtYjNiOS1kZjk2YzVkMTE1NzkiLCJjbHVzdGVyIjoiODYwMjkwNmYtNTQzNy00Y2NlLWIxNTAtN2MzMzg3ZGEzNmZhIiwiaWF0IjoxNzIyMjM2OTIzLCJuYmYiOjE3MjIyMzY5MjMsImV4cCI6MTcyMjI1MTMyMywiYXVkIjoibW9yaW8iLCJpc3MiOiJtb3JpbyIsInN1YiI6Im1vcmlvIn0.sij21XpVw2i6SjTZtms9Sl4WsTYh6wgcr0c79x7-6OQPaWam-Ne8t_mzcI5Opa8qOjdFBDBoRHjairzyURpQ-p0BmrDANp4gw17lAqvmgGySwTC-T0yqdRpvZLV85ZhSps3XqiTuWObOVztd3MOLc6xbbp-SEIk6VimzDWcSQbInDfTCbbx4OivWjIcpA6XGfVcXWWtZiJz7y8E8E2jrckV3jkqRUZuhZ_HIcOyh1LSKb4WWWybCcu-D6hC1VipX_oy2Q8227V-VY1Kgryxe-F8xckgBkIoFjdejVsz4UpkvWXsYEJEZjgKLC0zZEZJVaEJC3w6QpNj-nc5d5dgF0TDq_6T0GvTaoN_UZGBgYioGTd0wXHpw0Trzc0VQrN5O3yBYjnhsbwSWlhHlClSAbV_CCy2qUAyDOrXBGmOlIYN8YZ_eJe-wIYioISd9dd0h5rbTSjtMqpX8fDoRZv0jFraVDOk0eMwiGM_TKhsFfR3sx0samCt7k3nCTseLeufCxRUkBZmeoG7o0NrZ0tbTrUoS9XJX_PDK3v9u-Z1LqjmJe7nERG55gXQer-_a5yWn-LKWooAYFW3iLwZEpvAxQF_VtW2xoCkrj5BD9UOnotj6emHmK76oURrSd3waQ_EWmnwf86dSXPQiljp41jHt95V7jyN5P4my-ogotTKxoGA" https://example.morio.it/token
Cookie Authentication
While Bearer Authentication is most useful for automated access and scripts, in a browser it is often easier to rely on Cookie Authentication instead, which the Morio Management API supports as well.
The API will check the morio
cookie for JWT content, so place the JSON Web
Token in a cookie named morio
to use this way to authenticate.
A JSON representation of the request cookies would look like this:
{
"Cookie": "morio=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibG9jYWwudGVzdEFjY291bnQxNzIyMjM2OTIyMDQ4Iiwicm9sZSI6InVzZXIiLCJhdmFpbGFibGVfcm9sZXMiOlsidXNlciJdLCJoaWdoZXN0X3JvbGUiOiJ1c2VyIiwicHJvdmlkZXIiOiJsb2NhbCIsIm5vZGUiOiIzOWIwYjVmZC02NjQ4LTQxZjgtYjNiOS1kZjk2YzVkMTE1NzkiLCJjbHVzdGVyIjoiODYwMjkwNmYtNTQzNy00Y2NlLWIxNTAtN2MzMzg3ZGEzNmZhIiwiaWF0IjoxNzIyMjM2OTIzLCJuYmYiOjE3MjIyMzY5MjMsImV4cCI6MTcyMjI1MTMyMywiYXVkIjoibW9yaW8iLCJpc3MiOiJtb3JpbyIsInN1YiI6Im1vcmlvIn0.sij21XpVw2i6SjTZtms9Sl4WsTYh6wgcr0c79x7-6OQPaWam-Ne8t_mzcI5Opa8qOjdFBDBoRHjairzyURpQ-p0BmrDANp4gw17lAqvmgGySwTC-T0yqdRpvZLV85ZhSps3XqiTuWObOVztd3MOLc6xbbp-SEIk6VimzDWcSQbInDfTCbbx4OivWjIcpA6XGfVcXWWtZiJz7y8E8E2jrckV3jkqRUZuhZ_HIcOyh1LSKb4WWWybCcu-D6hC1VipX_oy2Q8227V-VY1Kgryxe-F8xckgBkIoFjdejVsz4UpkvWXsYEJEZjgKLC0zZEZJVaEJC3w6QpNj-nc5d5dgF0TDq_6T0GvTaoN_UZGBgYioGTd0wXHpw0Trzc0VQrN5O3yBYjnhsbwSWlhHlClSAbV_CCy2qUAyDOrXBGmOlIYN8YZ_eJe-wIYioISd9dd0h5rbTSjtMqpX8fDoRZv0jFraVDOk0eMwiGM_TKhsFfR3sx0samCt7k3nCTseLeufCxRUkBZmeoG7o0NrZ0tbTrUoS9XJX_PDK3v9u-Z1LqjmJe7nERG55gXQer-_a5yWn-LKWooAYFW3iLwZEpvAxQF_VtW2xoCkrj5BD9UOnotj6emHmK76oURrSd3waQ_EWmnwf86dSXPQiljp41jHt95V7jyN5P4my-ogotTKxoGA"
}
Basic Authentication
While we recommend using either Bearer or Cookie authentication with a JSON Web Token you obtained from the API, the API also supports using API Keys as credentials through Basic Authentication.
In this scheme, you use your username and password rather than a JSON Web Token.
You should construct the Authorization
header to hold the base-64 encoded value of username:password
prefixed by Basic
.
An example JSON representation of the headers would look like this:
{
"Authorization": "Basic MDFjNmJmMmEtZDBlYy00OWU4LTgwOTctOTNmOTZhYmNjZWQyOmU4YjZkZGIzZTExYzIyNjAwMzYzYzZjNDJjODQzYzM3MTRhM2M0YmI4YWZkMGRmMmUyYWVjOTExNWExYWNmZDEzMjEwMzRhMTVlZWI3ZWNiZDJiNzIwN2M2YzIyODYxOQ=="
}
Here too, you can send this header in curl:
curl -H "Authorization": "Basic MDFjNmJmMmEtZDBlYy00OWU4LTgwOTctOTNmOTZhYmNjZWQyOmU4YjZkZGIzZTExYzIyNjAwMzYzYzZjNDJjODQzYzM3MTRhM2M0YmI4YWZkMGRmMmUyYWVjOTExNWExYWNmZDEzMjEwMzRhMTVlZWI3ZWNiZDJiNzIwN2M2YzIyODYxOQ==" https://example.morio.it/docker/containers
Although for Basic Authentication, curl also supports the -u
flag to pass
username:password directly, no need to base-64 encode anything:
curl -u "apikey:apisecret" https://example.morio.it/docker/containers
When to (not) use Basic Authentication
While Basic Authentication is easier — no need to login to request a token — it is also an order of magnitude slower then Bearer or Cookie Authentication.
That is because both Bearer and Cookie authentication send the JSON Web Token. As we saw above, the token contains a payload that has everything we need to make a decision about whether or not to grant access. The only thing to do is to verify the cryptographic signature of the token.
Compare that to a Basic Authentication request where we need to reach out to the identity provider’s backend to lookup the user account, and then verify its credentials.
This round-trip to an identity provider’s backing service adds significant delay — perhaps barely noticeable to us humans, but it is still an order of magnitude slower to use Basic Authentication.
So, as a rule of thumb, we recommend that:
- You do not use Basic Authentication for more than 3 API requests in a row.
- If you need to make more than 3 API requests, use the
/login
endpoint to request a JSON Web Token, and use either Bearer or Cookie authentication for subsequent API requests.
Token expiry and renewal
The tokens issued by the API expire. Their expiry is set in the
MORIO_API_JWT_EXPIRY
preset
which has a default value of 12h
, or 12 hours.
At any time prior to the token’s expiry, you can get a new token from the
/token
endpoint to
reset the clock on your token expiry.
API Dependencies
The Morio Management API relies on the Core service to bootstrap itself, and on the proxy service to act as a reverse proxy.
As a result, any problem with the core or proxy services will also impact the API service.