Copyright © 2005-2021
Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.
Overview
Resources
Representation Formats
Accept
header denotes the demanded type. Find the type in the examples below.
Dates in JSON
Date or datetime fields are not treated specially in JSON. Within the scope of this API a date or datetime field is always expected and
rendered as JSON String in ISO8601 format with timezone information and milliseconds: yyyy-MM-dd’T’HH:mm:ss.SSSTZD
.
Embedded Entities
For the sake of convenience some response entities may included embedded entities or even parts of it. A reference to the actual entity is provided as HAL link as well.
Error Responses
Beside the actual representation of resources, the server may result an error response in JSON format that contains basic information about the error occurred. This information is additional to the standard HTTP status code and may help clients to identify the error cause in order to re-phrase and send the request again.
Currently there are two types of errors with their own response formats.
Server Declined Errors
This kind of errors are sent by the server runtime environment even before the request had a chance to be processed.
An example response looks like this:
{
"timestamp": 1512400854941,
"status": 500,
"error": "Internal Server Error",
"exception": "org.ameba.oauth2.InvalidTokenException",
"message": "JWT expired at 2017-12-04T15:04:43Z. Current time: 2017-12-04T15:20:54Z, ...",
"path": "/v1/transport-units?bk=00000000000000004711"
}
The JSON structure contains the following fields.
Property Name | Description |
---|---|
timestamp |
When the error occurred on server side |
status |
The http status of the error |
error |
A short error text |
exception |
Internal class name of the Java exception type |
message |
A more descriptive error text describing the error in detail |
path |
The part of the URI for the REST resource that was queried |
API Declined Errors
Those errors are thrown within the REST API validation and processing logic. For example, if a client request does not match the expected format or has produced an error on server side, the API will decline the request and return a response with status client-side error (4xx).
The structure of the response is aligned to the RFC7808. An example response looks like this:
{
"message": "LocationGroup with name [NOT_EXISTS] not found",
"messageKey": "COMMON.LOCATION_GROUP_NOT_FOUND",
"obj" : [ "NOT_EXISTS" ],
"httpStatus" : "404",
"class" : "String"
}
The JSON structure contains the following fields.
Property Name | Description |
---|---|
message |
A short error text |
messageKey |
An unique identifier across the API that can be used to identify and translate the error message on the client side |
obj |
An array of possible passed arguments to the message |
httpStatus |
The http status of the error |
class |
The arguments type |
Following message keys are currently used:
Message Key | Description | Action |
---|---|---|
not.found |
The requested resource has not been found |
The resource does not exist anymore or has never existed. The resource identifier must be verified |
Index
The initial HTTP request to retrieve information about all available resources looks like the following. The Index page is a public available resource and does not need any authentication.
GET /index HTTP/1.1
Host: localhost:8080
The Index
resource is returned in the response body with the response status of 200-OK. This main Index
lists all primary resource
entities to follow next.
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 347
{
"_links" : {
"user-index" : {
"href" : "http://localhost:8080/users/index"
},
"role-index" : {
"href" : "http://localhost:8080/roles/index"
},
"grant-index" : {
"href" : "http://localhost:8080/grants/index"
},
"client-index" : {
"href" : "http://localhost:8080/api/clients/index"
}
}
}
A client application only needs to know about the agreed link names and follow the corresponding href
link to navigate to further
resources.
User
A User
represents a human user of the system, usually in front of an UI who interacts with the system. User
representations can be
created, modified and retrieved. An User
is also allowed to authenticate against an UAA endpoint.
User Index
An overview of all possible operations on Users
can be found on the User
index page that is retrieved with a GET
request:
GET /users/index HTTP/1.1
Host: localhost:8080
And the server responds with a HAL+JSON
representation to further operations:
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 506
{
"_links" : {
"users-findall" : {
"href" : "http://localhost:8080/users"
},
"users-findbypkey" : {
"href" : "http://localhost:8080/users/pKey"
},
"users-create" : {
"href" : "http://localhost:8080/users"
},
"users-save" : {
"href" : "http://localhost:8080/users"
},
"users-saveimage" : {
"href" : "http://localhost:8080/users/pKey/details/image"
},
"users-delete" : {
"href" : "http://localhost:8080/users/pKey"
}
}
}
Create an User
To create a new User
instance, a POST
request must be send to the server with the mandatory fields of the User
in the request body
POST /users HTTP/1.1
Content-Type: application/json
Content-Length: 77
Host: localhost:8080
{
"links" : [ ],
"username" : "admin2",
"email" : "admin@example.com"
}
Path | Type | Description |
---|---|---|
|
|
The unique name of the User in the system |
|
|
The email address used by the User, unique in the system |
If the User
has been created successfully, the server returns the URI to the created resource in the Location
header:
HTTP/1.1 201 Created
Location: http://localhost:8080/users/e9790a59-91a8-4628-bba9-6a9670b12f84/
Content-Type: application/hal+json
Content-Length: 144
{
"pKey" : "e9790a59-91a8-4628-bba9-6a9670b12f84",
"username" : "admin2",
"externalUser" : false,
"locked" : false,
"enabled" : true
}
If an User
with the same name already exists the server returns an error:
HTTP/1.1 409 Conflict
Content-Type: application/hal+json
Content-Length: 112
{
"message" : "User with username already exists",
"messageKey" : "already.exists",
"httpStatus" : "409"
}
Find all Users
To find and retrieve an array of all existing Users
a client may call a GET
request:
GET /users HTTP/1.1
Host: localhost:8080
and returns either an array of Users
…
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 539
[ {
"links" : [ ],
"pKey" : "96baa849-dd19-4b19-8c5e-895d3b7f405d",
"username" : "tester",
"externalUser" : false,
"lastPasswordChange" : "2020-06-22T19:02:47.33044Z",
"locked" : false,
"enabled" : true,
"expirationDate" : "2020-06-23T19:02:45.054756Z",
"fullname" : "Mister Jenkins",
"details" : {
"description" : "Just a test user",
"comment" : "testing only",
"phoneNo" : "001-1234-56789",
"im" : "Skype:testee",
"office" : "Off. 815",
"department" : "Dep. 1",
"gender" : "FEMALE"
}
} ]
or an empty array, but always with a 200-OK
.
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 3
[ ]
Find an User by persistent key
A newly created User
can be retrieved by following the URI in the Location
header of the response. This URI points to the created
resource:
GET /users/e9790a59-91a8-4628-bba9-6a9670b12f84/ HTTP/1.1
Host: localhost:8080
If the resource exists the server responds with a 200-OK
and the User
representation in the response body.
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 144
{
"pKey" : "e9790a59-91a8-4628-bba9-6a9670b12f84",
"username" : "admin2",
"externalUser" : false,
"locked" : false,
"enabled" : true
}
Modify an existing User
An existing User
instance can be modified by sending a PUT
request with the User
representation as request body.
PUT /users HTTP/1.1
Content-Type: application/json
Content-Length: 164
Host: localhost:8080
{
"links" : [ ],
"pKey" : "e9790a59-91a8-4628-bba9-6a9670b12f84",
"username" : "superuser",
"externalUser" : false,
"locked" : true,
"enabled" : false
}
If the server has correctly updated the User
the response is a:
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 147
{
"pKey" : "b008ad2f-b53a-4908-9f25-f9d330e4fcc8",
"username" : "superuser",
"externalUser" : false,
"locked" : true,
"enabled" : false
}
Update the image of an existing User
To set the image of an existing User
a client needs to send a PATCH
request along the image in the UserDetails
.
PATCH /users/e9790a59-91a8-4628-bba9-6a9670b12f84/details/image HTTP/1.1
Content-Type: application/octet-stream
Content-Length: 18572
Host: localhost:8080
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
If the server has correctly updated the Users
image the response looks like:
HTTP/1.1 200 OK
Get the User Details (OAuth2 UserDetails)
An endpoint exists to get the details of the current logged-in User
from. An OAuth2 Access Token must be provided as Bearer token in order
to access the endpoint.
GET /oauth/userinfo HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MTgzOTMwNTIsInVzZXJfbmFtZSI6InRlc3RlciIsImp0aSI6IjUyYmI4MjQ0LTMyNjEtNGEwNS1hNzI0LTM4MmQyNzQxMmY3OCIsImNsaWVudF9pZCI6ImdhdGV3YXkiLCJzY29wZSI6WyJnYXRld2F5Il19.5j_YtzgwBhyDW5f2C-BIgf5BdwD-ikL_3gnLLqMfl90
Host: localhost:8080
If the access token is valid and the server granted access to the resource, a JSON object with the user details is returned.
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 307
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
{
"sub" : "tester",
"gender" : "FEMALE",
"name" : "tester",
"phone_number" : "001-1234-56789",
"given_name" : "Mister Jenkins",
"family_name" : "Mister Jenkins",
"email" : "tester.tester@example.com",
"picture" : "http://localhost:8080/uaa/user/96baa849-dd19-4b19-8c5e-895d3b7f405d/image/"
}
Path | Type | Description |
---|---|---|
|
|
Subject is the logged in end-user |
|
|
The end-users gender |
|
|
Name of the end-user |
|
|
Her phone number |
|
|
The given name |
|
|
Her family name |
|
|
Her primary email address |
|
|
A link to a profile picture |
Delete an User
To finally delete all User
data a DELETE
request with the persistent key of the User
is required:
DELETE /users/e9790a59-91a8-4628-bba9-6a9670b12f84/ HTTP/1.1
Host: localhost:8080
If the User
is not assigned somewhere else (in Roles
) and it has been deleted successfully the server responds:
HTTP/1.1 204 No Content
Role
An User
could be assigned to multiple Roles
and act on behalf of a Role
. Additionally a Role
assigns Grants
to all the Users
that are assigned to this Role
. By doing so, a Role
is also a group of Grants
that can be assigned to multiple Users
.
Role Index
An overview of all possible operations on Roles
can be found on the Role
index page that is retrieved with a GET
request:
GET /roles/index HTTP/1.1
Host: localhost:8080
And the server responds with a HAL+JSON
representation to further operations:
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 325
{
"_links" : {
"roles-findall" : {
"href" : "http://localhost:8080/roles"
},
"roles-create" : {
"href" : "http://localhost:8080/roles"
},
"roles-save" : {
"href" : "http://localhost:8080/roles"
},
"roles-delete" : {
"href" : "http://localhost:8080/roles/pKey"
}
}
}
Find all Roles
To find and retrieve an array of all existing Roles
a role may call a GET
request:
GET /roles HTTP/1.1
Host: localhost:8080
and returns either an array of Roles
or an empty array, but always a 200-OK
.
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 240
[ {
"links" : [ ],
"pKey" : "1",
"name" : "ROLE_ADMIN",
"immutable" : true,
"description" : "Super user role"
}, {
"links" : [ ],
"pKey" : "2",
"name" : "ROLE_OPS",
"immutable" : true,
"description" : "Operator role"
} ]
Modify an existing Role
An existing Role
instance can be modified by sending a PUT
request with the Role
representation as request body. At least the name of
the Role
, as an identifying attribute must be set.
PUT /roles HTTP/1.1
Content-Type: application/json
Content-Length: 124
Host: localhost:8080
{
"links" : [ ],
"pKey" : "1",
"name" : "ROLE_SUPER",
"immutable" : false,
"description" : "Administrators role"
}
Path | Type | Description |
---|---|---|
|
|
The persistent key must be passed when modifying an existing instance |
|
|
The name as an identifying attribute of the existing Role, cannot be changed |
|
|
A description text to update |
|
|
Whether the Role is immutable or not |
If the server has correctly updated the Role
the response contains the updated representation:
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 142
{
"pKey" : "e58d08e9-cce2-49d1-af21-7088d448705e",
"name" : "ROLE_SUPER",
"immutable" : false,
"description" : "Administrators role"
}
If the name of the Role
to update is missing, the server responds with an error:
HTTP/1.1 406 Not Acceptable
Content-Type: application/hal+json
Content-Length: 75
{
"message" : "Role to save is a transient one",
"httpStatus" : "406"
}
Delete a Role
To finally delete all Role
data, a DELETE
request with the persistent key of the Role
is required:
DELETE /roles/1 HTTP/1.1
Host: localhost:8080
If the Role
has been deleted successfully the server responds:
HTTP/1.1 204 No Content
Grant
A Grant
represents a permission to perform an action. A Grant
can be assigned to a Role
and is always tied to some kind of action that
can be taken. It has a unique business key, that is used in API or UI to protect against unauthorized access.
Grant Index
An overview of all possible operations on Grants
can be found on the Grant
index page that is retrieved with a GET
request:
GET /grants/index HTTP/1.1
Host: localhost:8080
And the server responds with a HAL+JSON
representation to further operations:
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 99
{
"_links" : {
"grants-findall" : {
"href" : "http://localhost:8080/grants"
}
}
}
Find all Grants
To retrieve all existing Grants
from the server, a client simply needs to do a GET
request to the Grants
resource.
GET /grants HTTP/1.1
Host: localhost:8080
The server responds with a list representation of all Grants
or an empty list:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 344
[ {
"name" : "SEC_UAA_USER_LOOKUP",
"description" : "Permission to find Users"
}, {
"name" : "SEC_UAA_USER_CREATE",
"description" : "Permission to create Users"
}, {
"name" : "SEC_UAA_USER_MODIFY",
"description" : "Permission to modify Users"
}, {
"name" : "SEC_UAA_USER_DELETE",
"description" : "Permission to delete Users"
} ]
Client
A Client
represents a OAuth2 respectively OpenID Connect client that acts as a resource consumer and tries to access a protected resource
server. Mostly a Client
is an application or a software service.
Client Index
An overview of all possible operations on Clients
can be found on the Client
index page that is retrieved with a GET
request:
GET /api/clients/index HTTP/1.1
Host: localhost:8080
And the server responds with a HAL+JSON
representation to further operations:
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 357
{
"_links" : {
"clients-findall" : {
"href" : "http://localhost:8080/api/clients"
},
"clients-create" : {
"href" : "http://localhost:8080/api/clients"
},
"clients-save" : {
"href" : "http://localhost:8080/api/clients"
},
"clients-delete" : {
"href" : "http://localhost:8080/api/clients/pKey"
}
}
}
Create a Client
To create a new Client
instance, a POST
request must be send to the server with the mandatory fields of the Client
in the request body
POST /api/clients HTTP/1.1
Content-Type: application/json
Content-Length: 349
Host: localhost:8080
{
"links" : [ ],
"resourceIds" : "res",
"clientId" : "cliendId",
"clientSecret" : "secr3t",
"scope" : "client",
"authorizedGrantTypes" : "implicit",
"webServerRedirectUri" : "url",
"authorities" : "auth",
"accessTokenValidity" : 9999,
"refreshTokenValidity" : 8888,
"additionalInformation" : "info",
"autoapprove" : "false"
}
Path | Type | Description |
---|---|---|
|
|
The unique id of the client |
|
|
The clients secret used for authentication |
|
|
Duration how long the access token is valid |
|
|
Some additional descriptive text for the client |
|
|
A list of authorities |
|
|
The OAuth2 grant types the client is allowed to use |
|
|
If user consent is required this is set to false |
|
|
Duration how long a refresh token is valid |
|
|
A list of resource ids |
|
|
A list of scopes the client can ask for |
|
|
The OAuth2 redirect url |
If the Client
has been created successfully, the server returns the newly created resource in the response body:
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 383
{
"pKey" : "23424459-351e-4720-9fce-a97745d9f364",
"resourceIds" : "res",
"clientId" : "cliendId",
"clientSecret" : "secr3t",
"scope" : "client",
"authorizedGrantTypes" : "implicit",
"webServerRedirectUri" : "url",
"authorities" : "auth",
"accessTokenValidity" : 9999,
"refreshTokenValidity" : 8888,
"additionalInformation" : "info",
"autoapprove" : "false"
}
Find all Clients
To find and retrieve an array of all existing Clients
a client may call a GET
request:
GET /api/clients HTTP/1.1
Host: localhost:8080
and returns either an array of Clients
or an empty array, but always a 200-OK
.
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 372
[ {
"links" : [ ],
"pKey" : "1000",
"clientId" : "gateway",
"clientSecret" : "secret",
"scope" : "gateway",
"authorizedGrantTypes" : "password,authorization_code,refresh_token,implicit",
"webServerRedirectUri" : "http://localhost:8086/login/oauth2/code/gateway",
"accessTokenValidity" : 36000,
"refreshTokenValidity" : 36000,
"autoapprove" : "true"
} ]
Modify an existing Client
An existing Client
instance can be modified by sending a PUT
request with the Client
representation as request body.
PUT /api/clients HTTP/1.1
Content-Type: application/json
Content-Length: 368
Host: localhost:8080
{
"links" : [ ],
"pKey" : "1000",
"resourceIds" : "res",
"clientId" : "cliendId",
"clientSecret" : "secr3t",
"scope" : "client",
"authorizedGrantTypes" : "implicit",
"webServerRedirectUri" : "url",
"authorities" : "auth",
"accessTokenValidity" : 9999,
"refreshTokenValidity" : 8888,
"additionalInformation" : "info",
"autoapprove" : "false"
}
If the server has correctly updated the Client
the response contains the updated representation:
HTTP/1.1 200 OK
Content-Type: application/hal+json
Content-Length: 351
{
"pKey" : "1000",
"resourceIds" : "res",
"clientId" : "cliendId",
"clientSecret" : "secr3t",
"scope" : "client",
"authorizedGrantTypes" : "implicit",
"webServerRedirectUri" : "url",
"authorities" : "auth",
"accessTokenValidity" : 9999,
"refreshTokenValidity" : 8888,
"additionalInformation" : "info",
"autoapprove" : "false"
}
Delete a Client
To finally delete all Client
data, a DELETE
request with the persistent key of the Client
is required:
DELETE /api/clients/1000 HTTP/1.1
Host: localhost:8080
If the Client
has been deleted successfully the server responds:
HTTP/1.1 204 No Content