Identity Hub API Reference
Updated: June 2, 2020
Identity hubs expose a set of interfaces for reading and writing data to a DID's personal data store, and for synchronizing that data across all hub instances and devices. The APIs described on this page are part of a proposed standard for identity hub interaction. This allows developers to write their code once and support all identity hubs, regardless of where a DID chooses to run their hub.
Best practices
We recommend you keep the following in mind when programming against identity hubs:
- Adhere closely to the documented behavior on this page and in hub standards. This ensures that you won't take a dependency on any API behavior that may not be supported by other identity hub providers the user may use.
- Use DIF's identity hub client library/SDK if possible. The library abstracts away much of the complexity of identity hubs, and exposes a simple set of methods.
- Do not assume all identity hub services will offer similar performance levels or uptime. Your apps and services should be prepared to handle identity hubs that are offline or responding slowly. Once again, using DIF's client libraries will help in this capacity.
- Be prepared for breaking changes. At this time, identity hubs and client libraries are in early stage development. You should be prepared for APIs to change or be deprecated without notice.
Endpoint Discovery
The first step in using an identity hub is locating its DID and URL. If you are exclusively using Microsoft's identity hub cloud service, you can use the values listed immediately below. Alternatively, you can follow the endpoint discovery process outlined in our tutorial, which uses the InterfaceMap
object below.
Microsoft specific values
Currently the Microsoft identity hub cloud service uses the following parameters:
DID:
did:test:hub.id
URL:
https://beta.personal.hub.microsoft.com
InterfaceMap
The InterfaceMap
is a mechanism for describing the endpoints of an identity hub service in detail:
{
"@context": "https://schema.identity.foundation/1.0/hub",
"@type": "IdentityHubConfiguration",
"endpoints": [{
"@context": "http://schema.identity.foundation/1.0/hub",
"@type": "InterfaceMap",
"interfaces": {
"Collections": "https://hub.azure.com/Collections",
"Profile": "https://www.foo.com/.identity/Profile",
"Actions": "https://id.bar.org/.identity/Actions",
...
}
},
{
"@context": "http://schema.identity.foundation/1.4/hub",
"@type": "InterfaceMap",
"interfaces": {
"Collections": "https://hub.azure.com/Collections",
"Profile": "https://www.foo.com/whatever-path/Profile",
"Actions": "https://id.bar.org/.identity/Actions",
...
}
}],
"signature": {
"kid": "did:btcs:456#key-1",
"value": "jv9323lavjsdav0d9ada2...",
"timestamp": "2018-10-24T18:39:10.10:00Z"
}
}
Hub implementations using the InterfaceMap
can choose to use a single URL for all interfaces they support, or may have different URLs for each. The format of each interface URL is not specified in this document.
Commits
Commits are the fundamental data type in identity hub's data model. Each object in hubs is represented as a series of commits.
Data Formats & Encodings
At this time, the only data format supported by hubs is JSON objects. JSON objects are encapsulated into JWSs and JWEs as described in the authentication section. Images, videos, streams, and other MIME types are not currently supported.
Commit
A commit is a JSON web token (JWT) that is signed by the author. The structure of an example commit is presented below:
// Each commit is a JWT using Flattened JSON serialization.
// The JWT contents are displayed below in decoded form.
{
"protected": {
"alg": "RS256",
"kid": "did:example:abc123#key-abc",
"interface": "Collections",
"context": "http://schema.org",
"type": "MusicPlaylist",
"operation": "update",
"committed_at": "2018-10-24T18:39:10.10:00Z",
"object_id": "3a9de008f526d239...",
"commit_strategy": "basic",
"sub": "did:example:abc123",
},
"header": {
"rev": "fe4fd3240ff1c68a...",
"iss": "did:example:123456"
},
"payload": {
"@context": "http://identity.foundation",
"@type": "MusicPlaylist",
"@id": "foo",
"name": "A modified playlist",
"tracks": []
},
"signature": "j3irpj90af992l..."
}
The JWT payload is the commit contents. The header values must be the following:
Header | Description |
---|---|
alg |
Standard JWT header. Indicates the algorithm used to sign the JWT. |
kid |
Standard JWT header. The value should take the form {did}#{key-id} . Another app can take this value, resolve the DID, and find the indicated public key that can be used for signature validation of the commit. |
interface |
Must be one of Collections , Profile , Actions , or Permissions . |
context |
The context of the object. This, along with type , indicates the type of object that is being created. |
type |
The type of the object. This, along with context , indicates the type of object that is being created. |
operation |
Must be one of create , update , or delete . |
committed_at |
The time at which the commit is taking place. |
commit_strategy |
Must be basic . See the hub overview for more details. |
sub |
The DID of the user whose hub is being accessed; in other words, the hub owner's DID. |
object_id |
The unique ID of the object this commit pertains to. The object ID value for an object is the rev of the commit that creates the object. |
header.rev |
The unique ID for this commit, which can be constructed by taking the SHA-256 hash of the protected and payload values of the commit concatenated by a . character. |
header.iss |
The DID of the issuer of the commit. Must match the DID used in the kid property of the commit protected headers. |
Basic Requests & Responses
WriteRequest
A WriteRequest
is used for submitting new commits to hubs. This includes creating, updating, and deleting data.
{
"@context": "https://schema.identity.foundation/0.1",
"@type": "WriteRequest",
"iss": "did:example:123456",
"aud": "did:example:some-hub",
"sub": "did:example:abc123",
"commit": <Commit>
}
Property | Description |
---|---|
@context |
Must be https://schema.identity.foundation/0.1 . |
@type |
Must be WriteRequest . |
iss |
Issuer. The DID of the party sending the request. The keys for this DID will be used to encrypt responses from the hub. |
aud |
Audience. The DID of the hub receiving the request. We got this DID during the hub endpoint discovery step above. The keys for this DID will be used to encrypt requests to the hub. |
sub |
Subject. The DID of the user who owns the hub where the data will be stored. |
commit |
A commit, in JWS Flattened JSON Serialization format. This is an alternative representation of a JWT. It can be easily constructed by splitting the parts (header, body, signature) of a conventional compact serialized JWT and placing them in the relevant properties (protected, payload, signature). An additional header property may also be specified, but is not protected by the signature. |
WriteResponse
A WriteResponse
is returned in the event of a successful write.
{
"@context": "https://schema.identity.foundation/0.1",
"@type": "WriteResponse",
"developer_message": "completely optional",
"revisions": ["3a9de008f526d239..."]
}
Property | Description |
---|---|
@context |
Must be https://schema.identity.foundation/0.1 . |
@type |
Must be WriteResponse . |
revisions |
An array of rev values, each of which represents a commit for the object that has been modified. |
ObjectQueryRequest
An ObjectQueryRequest
can be used to look up objects of a certain type in a hub.
{
"@context": "https://schema.identity.foundation/0.1",
"@type": "ObjectQueryRequest",
"iss": "did:example:123456",
"aud": "did:example:some-hub",
"sub": "did:example:abc123",
"query": {
"interface": "Collections",
"context": "http://schema.org",
"type": "MusicPlaylist",
"object_id": ["3a9de008f526d239..", "a8f3e7..."]
}
}
Property | Description |
---|---|
@context |
Must be https://schema.identity.foundation/0.1 . |
@type |
Must be ObjectQueryRequest . |
iss |
Issuer. The DID of the party sending the request. The keys for this DID will be used to encrypt responses from the hub. |
aud |
Audience. The DID of the hub receiving the request. The keys for this DID will be used to encrypt requests to the hub. |
sub |
Subject. The DID of the user who owns the hub where the data will be stored. |
query.interface |
One of Collections , Actions , Permissions , or Profile . Collections is most commonly used for data storage. |
query.context |
This value, along with type , indicates the type of object that is being queried for. |
query.type |
This value, along with context , indicates the type of object that is being queried for. |
query.object_id |
This optional value can be provided if the query should be restricted to one or more known objects, instead of all objects of the provided type. |
ObjectQueryResponse
An ObjectQueryResponse
is returned after a successful ObjectQueryRequest
.
{
"@context": "https://schema.identity.foundation/0.1",
"@type": "ObjectQueryResponse",
"developer_message": "completely optional",
"objects": [
{
"interface": "Collections",
"context": "http://schema.org",
"type": "MusicPlaylist",
"id": "3a9de008f526d239...",
"created_by": "did:example:abc123",
"created_at": "2018-10-24T18:39:10.10:00Z",
"sub": "did:example:abc123",
"commit_strategy": "basic",
},
]
}
Property | Description |
---|---|
@context |
Must be https://schema.identity.foundation/0.1 . |
@type |
Must be ObjectQueryResponse . |
objects[i].interface |
The hub interface where the object was retreived from. |
objects[i].context |
This value, along with type , indicates the type of the object. |
objects[i].type |
This value, along with context , indicates the type of the object. |
objects[i].id |
The unique object_id for this object. The object_id for an object is the commit id (rev ) of the commit that initally created the object. |
objects[i].created_by |
The DID of the party that created the object. |
objects[i].created_at |
The time at which the object was initally created. |
objects[i].sub |
The DID that owns the object. |
objects[i].commit_strategy |
Must be basic . See the hub overview for more details. |
CommitQueryRequest
A CommitQueryRequest
returns the details of commits for particular objects.
{
"@context": "https://schema.identity.foundation/0.1",
"@type": "CommitQueryRequest",
"iss": "did:example:123456",
"aud": "did:example:some-hub",
"sub": "did:example:abc123",
"query": {
"object_id": ["3a9de008f526d239..."],
}
}
Property | Description |
---|---|
@context |
Must be https://schema.identity.foundation/0.1 . |
@type |
Must be CommitQueryRequest . |
iss |
Issuer. The DID of the party sending the request. The keys for this DID will be used to encrypt responses from the hub. |
aud |
Audience. The DID of the hub receiving the request. The keys for this DID will be used to encrypt requests to the hub. |
sub |
Subject. The DID of the user who owns the hub where the data will be stored. |
query.object_id |
The object_id of the object whose commits we want to read. |
CommitQueryResponse
A CommitQueryResponse
is returned after a successful CommitQueryRequest
.
{
"@context": "https://schema.identity.foundation/0.1",
"@type": "CommitQueryResponse",
"developer_message": "completely optional",
"commits": [<Commit>]
}
Property | Description |
---|---|
@context |
Must be https://schema.identity.foundation/0.1 . |
@type |
Must be CommitQueryResponse . |
commits |
An array of commits, in JSON serialized JWT format, that modify the object. The format of each commit is described in the above sections. |
ErrorResponse
An ErrorResponse
may be returned in response to any of the requests above.
{
"@context": "https://schema.identity.foundation/0.1",
"@type": "ErrorResponse",
"error_code": "ABC123",
"developer_message": "An error has occurred."
}
Property | Description |
---|---|
@context |
Must be https://schema.identity.foundation/0.1 . |
@type |
Must be ErrorResponse . |
error_code |
A unique error code that describes the error and can be handled by application code. See below section for details. |
developer_message |
A helpful message to developers to assist in debugging. |
Error Codes
The following values may be returned in the error_code
field for hub responses.
Error Code | Description |
---|---|
bad_request |
The request could not be completed because it was malformed. Cases include: - the request JWE could not be decrypted - the response JWE could not encrypted - a required property was missing - an invalid value was provided in request |
authentication_failed |
The client could not be authenticated, because the request JWS could not be verified using the DID keys of the DID provided in the iss property. |
permissions_required |
The request is denied because the DID in the iss field has not be granted sufficient permission to perform the operation. |
not_found |
The resource requested could not be found in the hub. |
too_many_requests |
The client is being throttled, and should wait before retrying any requests. |
server_error |
An unexpected or unhandled error occurred on the hub. |
not_implemented |
The operation requested includes a standard hub feature that is not supported by this implementation of the hub. |
service_unavailable |
The hub service is temporarily not available and requests should not be retried. |
temporarily_unavailable |
The hub service experienced a transient error and the request should be retried at a later time. |
Paging
In a successful ObjectQueryResponse
or CommitQueryResponse
, the results returned may exceed the allowable size limit for responses. In these cases, the results can be paged using a skip_token
.
{
"@context": "https://schema.identity.foundation/0.1",
"@type": "ObjectQueryResponse",
"objects": [
{
"context": "http://schema.org",
"type": "MusicPlaylist",
"id": "3a9de008f526d239...",
"created_at": "2018-10-24T18:39:10.10:00Z",
"sub": "did:example:abc123",
"commit_strategy": "basic",
},
...
],
"skip_token": "ajfl43241nnn1p;u9390",
}
To use a skip_token
key value to get additional results, re-submit your original query with the skip_token
key and key value in the query
property.
If a response does not contain a skip_token
, then there are no more results for the client to fetch from the hub. Due to filtering performed in the Hub, it's possible that you may receive one or more responses which contains no results, however this does not necessarily indicate that no more results are available. Your app should continue to query until no skip_token
is returned.
A read request to a hub's collection interface that uses the skip_token
property:
Request
{
"@context": "https://schema.identity.foundation/0.1",
"@type": "ObjectQueryRequest",
"iss": "did:example:123456",
"aud": "did:example:some-hub",
"sub": "did:example:abc123",
"interface": "Collections",
"query": {
"context": "http://schema.org",
"type": "MusicPlaylist",
"skip_token": "ajfl43241nnn1p;u9390"
}
}
Authentication
All requests and responses above are encoded into a JWE format that is both signed and encrypted by the sender using the DID keys of the hub and the client. This allows the hub to authenticate the client and secure any messages exchanged. For details on creating JWEs, please refer to our tutorial.
Authorization
By rule, the DID that owns an identity hub always has full access to read, modify, write, and delete any and all data in the hub. The owner DID can create PermissionGrant
objects in their hub that grant other DIDs the ability to access data.
PermissionGrant
{
"@context": "https://identity.foundation/0.1",
"@type": "PermissionGrant",
"owner": "did:example:12345",
"grantee": "did:example:67890",
"context": "https://schema.org",
"type": "MusicPlaylist",
"allow": "CRUD",
}
Property | Description |
---|---|
@context |
Must be https://schema.identity.foundation/0.1 . |
@type |
Must be ErrorResponse . |
owner |
The DID that owns the data and the hub. |
grantee |
The DID that access is being granted to. |
context |
The type of data that is being accessed. |
type |
The type of data that is being accessed. |
allow |
Allows Create C , Read R , Update U , and Delete D . |
HTTP Requests
Once hub requests and responses have been constructed and encapsulated in a JWE, they must be sent to the identity hub service over HTTP. A request must use the POST
method with the following values:
POST / HTTP/1.1
Host: beta.personal.hub.microsoft.com
Content-Type: application/jwt
Content-Length: 1283
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ...
Responses are returned as JWEs as well. Hubs usually use a status code of 200
, but may use other 2**
error code values to indicate success. If a 2**
status code is returned, the response body must contain a properly formed JWE. Note that a 200
does not necessarily indicate a successful hub request; the JWE returned may still contain an error response inside.
HTTP/1.1 200 OK
Date: Mon, 27 Jul 2018 12:28:53 GMT
Content-Length: 501
Content-Type: application/jwt
Connection: Closed
eyJraWQiOiJkaWQ6dGVzdDpodWIuaWJrR...
A JWE cannot be returned, however, in the following cases:
- if the client's DID public keys cannot be resolved.
- if the client's request was improperly encrypted, so the client's DID is unknown.
- if the client's request was improperly signed, so the client could not be authenticated.
- if a server error occurred while retrieving keys or encrypting the JWE response.
- if the client and hub do not support the same signing or encryption algorithms.
- if the client is being throttled by a reverse proxy/load balancer/gateway.
In these cases, the HTTP response is returned with an error status and a JSON formatted response containing additional information. If there was a problem with the client's request, or any problem fetching or using the client's DID keys:
HTTP/1.1 400 Bad Request
Date: Mon, 27 Jul 2018 12:28:53 GMT
Content-Length: 124
Content-Type: application/json
Connection: Closed
{
"error_code": "ABC123",
"developer_message": "Unable to verify signature of JWE in request",
}
If the server encountered an error during JWE parsing or construction:
HTTP/1.1 500 Server Error
Date: Mon, 27 Jul 2018 12:28:53 GMT
Content-Length: 124
Content-Type: application/json
Connection: Closed
{
"error_code": "ABC123",
"developer_message": "Temporary server error",
}
If the server is throttling the client due to too many requests:
HTTP/1.1 429 Too Many Requests
Date: Mon, 27 Jul 2018 12:28:53 GMT
Content-Length: 124
Content-Type: application/json
Retry-After: 120
Connection: Closed
{
"error_code": "ABC123",
"developer_message": "Too many requests",
}
Hubs may also use other 4**
and 5**
status codes to indicate client and server error responses, respectively.
See something missing? We'd love your feedback and input on the Verifiable Credentials preview. Please contact us. When you use Microsoft DID Services, you agree to the DID Preview Agreement and the Microsoft Privacy Statement.