Skip to content

Acquiring an agent access token

Each onboarded agent is required to get an access token in order to use any services offered by MindSphere. MindSphere grants access tokens to clients for which token generation and grants comply with the rules of the OAuth 2.0 authorization framework.

MindSphere receives token requests (HTTP POST) from clients and grants access tokens back to them (HTTP 200 OK). Before granting an access token, the Access Token service performs the following checks:

  1. The token request contains mandatory and expected headers.
  2. The client is a known client (exists in the database).
  3. The client status is ONBOARDED.

Granting of access tokens is provided by the token endpoint of the Agent Management Service. This is a sample client access token request expected by MindSphere:

1
2
3
4
5
6
POST /api/agentmanagement/v3/oauth/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost: 8061
content-length: 510
Connection: keep-alive
grant_type=client_credentials&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhN2VhYjA5MTEzOTg0OGJiOWU0Mzg5ZDIzZTkzNzhiOCIsInN1YiI6ImE3ZWFiMDkxMTM5ODQ4YmI5ZTQzODlkMjNlOTM3OGI4IiwiYXVkIjpbInNvdXRoZ2F0ZSJdLCJpYXQiOjE1MTM2OTAzNzQsIm5iZiI6MTUxMzY5MDM3NCwiZXhwIjoxNTE0Mjk1MTc0LCJqdGkiOiI1NzIzZDg2NWNlNTMxMzM1Iiwic2NoZW1hcyI6WyJ1cm46c2llbWVuczptaW5kc3BoZXJlOnYxIl0sInRlbiI6ImNvbm50ZW5hbnRvbmVxYSJ9.cli8RKPIUCt7VcP1yGjJvTA8dMR+kdBHotrLDvo4PqXCd1h71jlT3TPSoEAUjbwlm5YTu8RjJwq3cKobq18U7z7AVo+BmSopUIAO/ugyXWHNTpde0V9u8eDMVa3csZrOFwocQVTkI9zehXV81x++fI4hyLF004tUukLNsSglwYiogslhuK1qL8kmdgmTbdAu+ABE68VZe83pyyPJ2iHXZ83oxNElFx/lRZvzQC8B91yRQVO6+kUkDTj9wSr/Mf59DZ1HjpvZn1G0tYt43S4CEjtJSMfseg+kBx+uoqjSYOIVnq5bQYP+UctJRAMtUZJfgInltQGUKXvnqiKo9+RMaeeJTveNvq8EcHHHzeTuEwH3w9cUWGAk8zXax/T6kmTNorMBqQrATG3/UXyhI22x9ji8cY/NCydPVAK8t6+kSDn90znhJ3+S5ubTpx4frv8GG6CbxSaRh5SVJQdg2mG3XJcupxHljj9kQJmnEaP5kepU1LDp5GEHVhfRb0AKpWCG
Parameter Description
grant_type Defines the OAuth 2.0 access token flow requested by the client.
MindSphere supports only client_credentials.
client_assertion_type Defines the assertion type (assertion are defined in RFC 7521).
MindSphere supports only the jwt-bearer type assertion urn:ietf:params:oauth:client-assertion-type:jwt-bearer (for details see RFC 7523, Section 2.2 "Using JWTs for Client Authentication").
client_assertion Contains the assertion (self-signed JWT) signed (by the client) with client secret or client public key depending on the client security profile.

The request body parameters grant_type, client_assertion_type, client_assertion body and the headers Host, Content-Type are mandatory. If one of them is not present, an HTTP response 400 Bad Request will be returned. Logs will have more detail regarding what was wrong with the client request. As imposed by Siemens security rules, no details will be provided in the response returned to the agent.

Client requests contain a self-signed JWT, conveyed with the body parameter client_assertion. This client assertion is required to be signed with the credential data provided at the registration:

  • If a public key is provided to MindSphere during registration, the client assertion JWT needs to be signed with the private key.
  • If a shared secret is used during registration, the client needs to sign the client assertion JWT with the shared secret.

This is an example value of the parameter client_assertion:

1
client_assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhN2VhYjA5MTEzOTg0OGJiOWU0Mzg5ZDIzZTkzNzhiOCIsInN1YiI6ImE3ZWFiMDkxMTM5ODQ4YmI5ZTQzODlkMjNlOTM3OGI4IiwiYXVkIjpbInNvdXRoZ2F0ZSJdLCJpYXQiOjE1MTM2OTAzNzQsIm5iZiI6MTUxMzY5MDM3NCwiZXhwIjoxNTE0Mjk1MTc0LCJqdGkiOiI1NzIzZDg2NWNlNTMxMzM1Iiwic2NoZW1hcyI6WyJ1cm46c2llbWVuczptaW5kc3BoZXJlOnYxIl0sInRlbiI6ImNvbm50ZW5hbnRvbmVxYSJ9.cli8RKPIUCt7VcP1yGjJvTA8dMR+kdBHotrLDvo4PqXCd1h71jlT3TPSoEAUjbwlm5YTu8RjJwq3cKobq18U7z7AVo+BmSopUIAO/ugyXWHNTpde0V9u8eDMVa3csZrOFwocQVTkI9zehXV81x++fI4hyLF004tUukLNsSglwYiogslhuK1qL8kmdgmTbdAu+ABE68VZe83pyyPJ2iHXZ83oxNElFx/lRZvzQC8B91yRQVO6+kUkDTj9wSr/Mf59DZ1HjpvZn1G0tYt43S4CEjtJSMfseg+kBx+uoqjSYOIVnq5bQYP+UctJRAMtUZJfgInltQGUKXvnqiKo9+RMaeeJTveNvq8EcHHHzeTuEwH3w9cUWGAk8zXax/T6kmTNorMBqQrATG3/UXyhI22x9ji8cY/NCydPVAK8t6+kSDn90znhJ3+S5ubTpx4frv8GG6CbxSaRh5SVJQdg2mG3XJcupxHljj9kQJmnEaP5kepU1LDp5GEHVhfRb0AKpWCG

This is the decoded version of the client assertion:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{
  "alg": "RS256",
  "typ": "JWT"
}
{
  "iss": "a7eab091139848bb9e4389d23e9378b8",
  "sub": "a7eab091139848bb9e4389d23e9378b8",
  "aud": [
    "southgate"
  ],
  "iat": 1513690374,
  "nbf": 1513690374,
  "exp": 1514295174,
  "jti": "5723d865ce531335",
  "schemas": [
    "urn:siemens:mindsphere:v1"
  ],
  "ten": "conntenantoneqa"
}

Upon receiving a client access token request on the token endpoint, MindSphere checks the incoming request for the following:

Check Error case
Request contains Host header. Returns an HTTP response 400 Bad Request with the following body:

{"error": "invalid_request"}.
Request contains Content-Type header and content type equals application/x-www-form-urlencoded (case-insensitive). Returns an HTTP response 400 Bad Request with the following body:

{"error": "invalid_request"}
Request contains grant_type body parameter and grant type equals client_credentials (case-insensitive). Returns an HTTP response 400 Bad Request to the agent with the following body:

{"error": "invalid_request"}
Request contains client_assertion_type body parameter and client assertion type equals urn:ietf:params:oauth:client-assertion-type:jwt-bearer (case-insensitive). Returns an HTTP response 400 Bad Request with the following body:

{"error": "invalid_request"}
Request contains client_assertion body parameter and its value is present. Returns an HTTP response 400 Bad Request with the following body:

{"error": "invalid_request"}

Note

Pragma and Cache-Control headers are mandatory in the error response as stated in RFC 6749, Section 5 "Issuing An Access Token".

If all checks above succeed, the request is validated. MindSphere continues to verify the request parameters:

Check Error case
The method TokenRequestJwtValidatorService.validateJwt is called with the parameter client_assertion.

The method checks, if the provided client assertion is a valid JWT.

The method also checks, if the following JWT payload claims are present and their values are as expected:

iss: Check, if claim is present.
sub: Check, if claim is present.
aud: Check, if claim is present and equals to southgate.
iat: Check, if claim is present and is before or equal to current time.
nbf: Optional claim. Check, if claim is present and is before or equal to current time.
exp: Check, if claim is present and expired time is not before the current time.
schemas: Check, if header is present and equals to urn:siemens:mindsphere:v1 (since sent from client).
If JWT validation fails, an InvalidJwtException is thrown.

A log is generated containing a message explaining why the JWT validation failed.

The exception is handled with an HTTP response 400 Bad Request with the following body:

{"error": "invalid_grant"}
The method TokenRequestJwtValidatorService.checkJwtSignature is called with the client assertion and the agent entity record.

The method checks, if the JWT signature is correct and the stored secret for the agent is not expired.
If the client secret is expired, an AgentSecretExpiredException is thrown and mapped to an HTTP response 400 Bad Request with the following body:

{"error": "invalid_grant"}

If the JWT Signature is not correct, an InvalidSignatureException is thrown and mapped to an HTTP response 400 Bad Request with the following body:

{"error": "invalid_client"}
The method AgentEntityRetrievalService.retrieveAgentEntity is called with the client assertion.

The method extracts the sub claim from the client assertion and queries the agent entity database for the related record and retrieves it.
If no agent entity record is found for the extracted sub claim, an AgentNotFound is thrown.

If an agent entity record is found but the agent entity onboarded status is not equal to ONBOARDED, an AgentNotOnboardedException is thrown.

Both exceptions are handled with an HTTP response 400 Bad Request with the following body:

{"error": "invalid_client"}
The method AccessTokenService.createAccessToken is called with the agent Id and tenant Id.

The method creates a signed JWT (signed with the private key of the Agent Management) and returns an access token.
If the controller is unable to access its private key, an NoSuchAlgorithmException, IOException or InvalidKeySpecificationException is thrown.

All exceptions are handled with an HTTP response 500 Internal Error.

When all tests have been successfully passed, MindSphere returns an HTTP response 200 OK that holds an access token. The returned access token is actually a signed JWT, which is valid for 1 hour by default.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
    "access_token": "eyJraWQiOiJrZXktaWQtMSIsImFsZyI6IlJTMjU2IiwidHlwIjoiSldUIn0.eyJqdGkiOiJjYmIwMGFhZS0yMTU5LTQwNWMtOGZhZC0xOWQ1YWE4ZTQxMWMiLCJzY29wZSI6WyJ0ZW5hbnQtc2NvcGUiLCJtZHNwOmNvcmU6RGVmYXVsdEFnZW50Il0sImlzcyI6Imh0dHBzOi8vc291dGhnYXRlLmV1LWNlbnRyYWwtcmMubWluZHNwaGVyZS5pby9hcGkvYWdlbnRtYW5hZ2VtZW50LyIsInN1YiI6ImE3ZWFiMDkxMTM5ODQ4YmI5ZTQzODlkMjNlOTM3OGI4IiwiemlkIjoiYWdlbnRpYW0iLCJhdWQiOlsic291dGhnYXRlIl0sImlhdCI6MTUxMzY5MDM3NiwiZXhwIjoxNTEzNjkzOTc2LCJzY2hlbWFzIjpbInVybjpzaWVtZW5zOm1pbmRzcGhlcmU6aWFtOnYxIl0sInRlbiI6ImNvbm50ZW5hbnRvbmVxYSIsImNhdCI6ImFnZW50LXRva2VuOnYxIiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyJ9.LzuA10P8Wy_pGr3s_gCiTaCd82Oc6ts0CJNG5n8MK31Dk5bRDd9hESPP5CUQ0V3pb504HLwBSGL1dg_AF48CdI9Dv8iZ5z667ZCiWptTsfPMdCaLtEWr09S5XA1TZtnLE_hg-v5NeMOmQJOc4xK3aSBmup3Qjw_RFpIeImPHLgCdavp06pdOSIrZ8qPXhi6qBxSAqWOho0DoCAmWO8zp_d55AwdXxeVVudieG9GrQVgGhjQtoIpP8R_pZtJ1nvr6b59nazk1fGsVcGyP-mavQ3Snp9kI7EsT96EBtKLbjuUmsa2bi8ju8LRB0fo_TkIWdnU02vLDfzlx4ftETHm8zg",
    "token_type": "Bearer",
    "expires_in": 3600,
    "scope": [
        "tenant-scope",
        "mdsp:core:DefaultAgent"
    ],
    "jti": "cbb00aae-2159-405c-8fad-19d5aa8e411c"
}
Parameter Description Remarks
access_token A JWT signed by MindSphere itself With this token, the agent is allowed to consume MindSphere services.
token_type Type of token MindSphere only supports Bearer.
expires_in Validity duration of the token in seconds
scope Scopes for which this token is valid.
jti JWT Token Id

This is the decoded version of the access token:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
    "kid": "key-id-1",
    "alg": "RS256",
    "typ": "JWT"
}
{
    "jti": "cbb00aae-2159-405c-8fad-19d5aa8e411c",
    "scope": [
        "tenant-scope",
        "mdsp:core:DefaultAgent"
    ],
    "iss": "https://southgate.eu-central-rc.mindsphere.io/api/agentmanagement/",
    "sub": "a7eab091139848bb9e4389d23e9378b8",
    "zid": "agentiam",
    "aud": [
        "southgate"
    ],
    "iat": 1513690376,
    "exp": 1513693976,
    "schemas": [
        "urn:siemens:mindsphere:iam:v1"
    ],
    "ten": "conntenantoneqa",
    "cat": "agent-token:v1",
    "grant_type": "client_credentials"
}

Any questions left?

Ask the community


Except where otherwise noted, content on this site is licensed under the MindSphere Development License Agreement.