Introduction
Welcome to UserClouds! This page provides helpful resources for getting started and documents our APIs for:
Supported Langauges & Frameworks
We have API documentation & samples for:
- Pure HTTP
- Shell (via curl)
- Golang (native SDK)
- Python (coming soon)
- Typescript (coming soon)
You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.
Configuring Your Tenant
All of these examples assume you have configured a Tenant with the system. A Tenant is a dedicated data store for your application's user data with several APIs built on top: Plex (Authentication), IDP (User Store), and AuthZ (Authorization). These APIs are all callable via your Tenant's custom base URL, known as the "Tenant URL".
For OIDC-compliant authentication via Plex, you must also configure Plex Applications (which map to OAuth2/OIDC Clients).
You may sign up and configure your tenant in the Developer Console.
For all examples below, make sure to replace the sample values (Tenant URLs, nonces & random values, redirect URLs, app/client IDs & secrets, etc) with values appropriate to your application.
Authentication
Authentication is handled on the front-end by Plex, an OIDC/OAuth-conformant authentication API with support for multiple underlying IDentity Providers (IDPs) such as:
- UserClouds
- Auth0
- Cognito (coming soon)
Plex was built with flexibility in mind to allow for:
- Easy initial setup on UserClouds, ideal for new apps or apps without large existing user account pools.
- Non-disruptive migration to UserClouds from an existing IDP, ideal for when you want to keep existing user accounts & credentials but transparently migrate users to UserClouds without disruption.
- Long-term use of a 3rd party IDP, fronted by Plex, ideal for augmenting your current Idnetity system with UserClouds' rich Authorization, Delegation, and User Data Vault features.
In all 3 cases, you can configure your application to authenticate users via Plex, and set up Plex Applications in the Developer Console which are backed by UserClouds' IDP and/or a 3rd party IDP. This lets you control where the "source-of-truth" for authentication lives, while allowing you to leverage UserClouds features at any layer of the stack.
Getting Started
Setting up authentication in your application with UserClouds is a breeze using the OAuth2/OIDC libraries/frameworks available in virtually every major langauge.
Currently, UserClouds supports standard OAuth2 and OpenID Connect (OIDC) methods for authenticating users and non-user/service accounts across a variety of environments: web, mobile, server, machine-to-machine (M2M), etc.
To authenticate users or non-users, an application triggers an authentication "flow", which consists of 1 or more steps that allow a user or non-user account to prove their identity. On success, the application receives one or more tokens (typically JWTs) which attest to the identity (and possibly permissions) of the user or non-user account. An application here may refer to code running on a web/mobile/desktop client, server, etc. The specific flow you should use depends on the structure, trust model, and needs of the application. ID tokens are used to confirm identity, while Access Tokens are used to confirm permissions or scopes for a particular application. They are similar conceptually but should not be used interchangeably for security reasons.
For users to sign in your app, there are a few primary/recommended "flows":
Which flow you use depends on whether your application can securely store secrets (clients generally can't, while servers generally can), how & where the resulting ID and Access Tokens will be used (if at all), and how much you value flexibility/simplicity vs. a tightly controlled user experience on login.
To authenticate non-user services/machines (which must be able to store a secret), applications should use the Client Credentials Flow.
Authorization Code Flow (with or without Proof Key Code Exchange)
import "golang.org/x/oauth2"
prov, _ := oidc.NewProvider(context.Background(), "https://sample.tenant.userclouds.com")
oauthConfig := oauth2.Config{
ClientID: "5f107e226353791560f93164a09f7e0f",
Endpoint: prov.Endpoint(),
RedirectURL: "https://contoso.com/callback",
Scopes: []string{"openid <ADDITIONAL_SCOPES>"},
}
Without PKCE:
GET /oidc/authorize?response_type=code&client_id=5f107e226353791560f93164a09f7e0f&redirect_uri=https%3A%2F%contoso.com%2Fcallback&scope=openid+profile+email&state=n9ftgCrrLNQ7sfxnnFmNcabEn8hFvAypP6Hu625WtBk HTTP/1.1
Host: sample.tenant.userclouds.com
curl 'https://sample.tenant.userclouds.com/oidc/authorize?response_type=code&client_id=5f107e226353791560f93164a09f7e0f&redirect_uri=https%3A%2F%contoso.com%2Fcallback&&scope=openid+profile+email&state=n9ftgCrrLNQ7sfxnnFmNcabEn8hFvAypP6Hu625WtBk'
// Authorization Code Flow without Proof Key Code Exchange (PKCE)
url := oauthConfig.AuthCodeURL("n9ftgCrrLNQ7sfxnnFmNcabEn8hFvAypP6Hu625WtBk")
// Redirect user agent to URL authorize endpoint
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
With PKCE:
GET /oidc/authorize?response_type=code&client_id=5f107e226353791560f93164a09f7e0f&redirect_uri=https%3A%2F%contoso.com%2Fcallback&scope=openid+profile+email&state=n9ftgCrrLNQ7sfxnnFmNcabEn8hFvAypP6Hu625WtBk&code_challenge=fJy4Nvl38sFmKyYUMZC1klsg9kn5HKXDUHEdeIuZnyc&code_challenge_method=S256 HTTP/1.1
Host: sample.tenant.userclouds.com
curl 'https://sample.tenant.userclouds.com/oidc/authorize?response_type=code&client_id=5f107e226353791560f93164a09f7e0f&redirect_uri=https%3A%2F%contoso.com%2Fcallback&&scope=openid+profile+email&state=n9ftgCrrLNQ7sfxnnFmNcabEn8hFvAypP6Hu625WtBk&code_challenge=fJy4Nvl38sFmKyYUMZC1klsg9kn5HKXDUHEdeIuZnyc&code_challenge_method=S256'
// Authorization Code Flow *with* Proof Key Code Exchange (PKCE) using SHA256 (the only supported method)
url := oauthConfig.AuthCodeURL(
state,
oauth.SetAuthURLParam("code_challenge_method", "S256"),
oauth.SetAuthURLParam("code_challenge", "<CODE_CHALLENGE>"))
// Redirect user agent to URL authorize endpoint
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
The Authorization Code flow is the most commonly used and recommended way for client applications (web, mobile) to allow users to log in.
If the application can be trusted to hold a secret (e.g. a web application with secure backend), the standard Authorization Code flow can be used.
If the application cannot securely hold a secret (e.g. web single-page app or mobile app), and particularly if access tokens are needed, it should utilize the Proof Key Code Exchange feature to prevent token hijacking.
Request
Because this is a GET
request, all parameters should be specified as query parameters in the URL.
Parameter | Type | Required? | Description |
---|---|---|---|
response_type | string | yes | code |
client_id | string | yes | The Client ID of a registered app/client in your UserClouds tenant. |
redirect_uri | string | yes | A URL to your application where the user agent will be redirected on completion. Must use https:// for production web apps, or a mobile custom scheme for mobile apps. Can use http:// for localhost and development tenants. |
scope | string | yes | Must specify openid in order to get an ID token from the token exchange endpoint later. May also specify profile , email , or other common scopes (see OIDC Spec for details). |
state | string | yes | An application-defined value used for 2 purpose: encode application state/context for a request, and to prevent CSRF attacks. See OAuth Security Topics for details. |
code_challenge_method | string | no | Indicates that PKCE should be used with a given method. Only 'S256' (SHA 256) is currently supported. |
code_challenge | string | no | A value generated by applying code_challenge_method (i.e. SHA 256) to a code_verifier value generated by the client. See the PKCE spec for more details. NOTE: this value is required iff code_challenge_method is specified. |
Response
On Success:
HTTP/1.1 302 Found
Location: https://contoso.com/callback?code=VieHyGShFqT57%2FjSeqTxQQEraGKhkYK0IMIyFzRRziQKy6G7eMPXDy0s8AiWSwNy&state=n9ftgCrrLNQ7sfxnnFmNcabEn8hFvAypP6Hu625WtBk
On Error:
HTTP/1.1 302 Found
Location: https://contoso.com/callback?error=invalid_grant&error_description=The+credentials+were+invalid
If the request is valid, the immediate GET
call to the authorize endpoint will redirect to Plex's internal endpoint(s) for the user to perform an interactive login. After the user sucessfully authenticates (or in case of an error in the process), the user agent will ultimately be redirected (HTTP 302) to the application-provided (and pre-registered) redirect URL, unless the redirect URL and/or Client ID are invalid (in which case the response will be a 400 Bad Request
).
Parameter | Type | Condition | Description |
---|---|---|---|
code | string | success | Cryptographically secure token which can be exchanged with the Token endpoint. |
state | string | success | The application-defined value passed in to the Authorize call. The client should validate that this matches to prevent attacks (hijacks, replays, etc.). |
error | string | failure | One of the OAuth/OIDC-spec defined error values. See the OAuth 2.0 spec for more details. |
error_description | string | failure | A human readable explanation of the error. |
Hybrid Flow
Docs coming soon.
Implicit Flow with Form Post
Docs coming soon.
Token Exchange for Authorization Code Flow (with or without Proof Key Code Exchange)
To exchange an authorization code for an access and/or ID token, use this code:
POST /oidc/token HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&client_id=5f107e226353791560f93164a09f7e0f&client_secret=iStpcFf3gfiUjnsbWGFY0C9aWkPzDqT14eyp23ysKuI6iBbOAWcode=VieHyGShFqT57%2FjSeqTxQQEraGKhkYK0IMIyFzRRziQKy6G7eMPXDy0s8AiWSwNy&redirect_uri=https%3A%2F%contoso.com%2Fcallback&code_verifier=iyMU3Af48ZZSPCbJGSxaUGmUJa-6uGiyTq5dwOvuvpg
curl --X POST \
-H 'content-type: application/x-www-form-urlencoded' \
-d '{"response_type":"code", "client_id":"5f107e226353791560f93164a09f7e0f", "client_secret":"iStpcFf3gfiUjnsbWGFY0C9aWkPzDqT14eyp23ysKuI6iBbOAW", "code":"VieHyGShFqT57%2FjSeqTxQQEraGKhkYK0IMIyFzRRziQKy6G7eMPXDy0s8AiWSwNy", "redirect_uri":"https://contoso.com/callback" "code_verifier":"iyMU3Af48ZZSPCbJGSxaUGmUJa-6uGiyTq5dwOvuvpg"}'
'https://sample.tenant.userclouds.com/oidc/token'
import "golang.org/x/oauth2"
prov, _ := oidc.NewProvider(context.Background(), "https://sample.tenant.userclouds.com")
oauthConfig := oauth2.Config{
ClientID: "5f107e226353791560f93164a09f7e0f",
ClientSecret: "iStpcFf3gfiUjnsbWGFY0C9aWkPzDqT14eyp23ysKuI6iBbOAW", // Only specified when NOT using PKCE
Endpoint: prov.Endpoint(),
RedirectURL: "https://contoso.com/callback",
}
// Authorization Code Flow without Proof Key Code Exchange (PKCE)
tokenResponse, err := oauthConfig.Exchange(ctx, "VieHyGShFqT57%2FjSeqTxQQEraGKhkYK0IMIyFzRRziQKy6G7eMPXDy0s8AiWSwNy")
// -- OR --
// Authorization Code Flow *with* Proof Key Code Exchange (PKCE) using SHA256 (the only supported method)
tokenResponse, err := oauthConfig.Exchange(ctx, "VieHyGShFqT57%2FjSeqTxQQEraGKhkYK0IMIyFzRRziQKy6G7eMPXDy0s8AiWSwNy", oauth.SetAuthURLParam("code_verifier", "iyMU3Af48ZZSPCbJGSxaUGmUJa-6uGiyTq5dwOvuvpg"))
if err { ... }
rawIDToken, ok := tokenResponse.Extra("id_token").(string)
if !ok { ... }
accessToken := tokenResponse.AccessToken
The application uses this endpoint to exchange the code
(returned after successful authorization) for a access_token
and/or id_token
(depending on the authorization flow used).
See Authorization Code Flow and Hybrid Flow for details on how to get a code
in the first place.
Request
This is a POST
request with all parameters form encoded in the body.
Parameter | Type | Required? | Description |
---|---|---|---|
grant_type | string | yes | authorization_code |
client_id | string | yes | The Client ID of a registered app/client in your UserClouds tenant. |
client_secret | string | no | The Client Secret of a registered app/client in your UserClouds tenant. Note that this is used only for the non-PKCE flow. |
redirect_uri | string | yes | A URL to your application where the user agent will be redirected on completion. Must use https:// for production web apps, or a mobile custom scheme for mobile apps. Can use http:// for localhost and development tenants. |
code_verifier | string | no | If PKCE was used to issue the authorization code, then this value must be specified and valid for the token exchange instead of client_secret . See the PKCE spec for more details. |
Response
TODO: refresh token support, token expiry
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token":"<ACCESS_TOKEN>",
"id_token":"<ID_TOKEN>",
"token_type":"Bearer",
}
If the request is valid, the endpoint returns a json struct with an access token and/or ID token (depending on the scopes of the original request), as well as the token type which is always "Bearer".
Parameter | Type | Condition | Description |
---|---|---|---|
access_token | string | success | Cryptographically secure token which can be used to make API calls. |
id_token | string | success | A raw three-part JWT which contains information about the resource owner / user. |
token_type | string | success | Always "Bearer" |
Refresh Token Exchange
Docs coming soon.
Client Credentials Flow
Docs coming soon.
Social Login
To access the underlying social IDP's token (eg. to access Google APIs directly on behalf of the user)
GET /social/underlying HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer [access_token]
{
"RawIDToken":"eyJ...",
"AccessToken":"ya29...",
"Profile": {
"email":"me@example.org",
"email_verified":true,
"family_name":"Mine",
"given_name":"Me",
"hd":"example.org",
"locale":"en",
"name":"Me Mine",
"picture":"https://lh3.googleusercontent.com/a/...",
"sub":"123"
},
"Claims": {
"name":"Me Mine",
"email":"me@exampke.org",
"email_verified":true,
"picture":"https://lh3.googleusercontent.com/a/...",
"sub":"123"
}
}
curl -X GET \
-H 'Authorization: Bearer [access_token]'
https://sample.tenant.userclouds.com/social/underlying
Plex exposes the underlying social tokens to enable using Google / Facebook / etc APIs directly if your application requires that.
Calling this endpoint requires the access token of the user who logged in via social login. (Note: we have plans in the future to enable offline access to these tokens using M2M auth, but haven't rolled it out yet).
Please contact support@userclouds.com to enable this, as it is disabled by default for security reasons.
Invites
Send Invite
TODO: should
"expires"
be an int64 unix timestamp?TODO: bearer token
POST /invite/send HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/json
{
"invitee_email": "alice@contoso.com",
"inviter_user_id": "68d69e31-6423-43e7-8e1b-c44956360410",
"client_id": "5f107e226353791560f93164a09f7e0f",
"state": "n9ftgCrrLNQ7sfxnnFmNcabEn8hFvAypP6Hu625WtBk",
"redirect_url": "https://contoso.com/invitecallback",
"invite_text": "Alice is inviting you to join the group",
"expires": "2022-03-28T01:48:31.267756Z"
}
curl -X POST \
-H 'Content-Type: application/json' \
-d '{ "invitee_email": "alice@contoso.com", "inviter_user_id": "68d69e31-6423-43e7-8e1b-c44956360410", "client_id": "5f107e226353791560f93164a09f7e0f", "state": "n9ftgCrrLNQ7sfxnnFmNcabEn8hFvAypP6Hu625WtBk", "redirect_url": "https://contoso.com/invitecallback", "invite_text": "Alice is inviting you to join the group", "expires": "2022-03-28T01:48:31.267756Z" }' 'https://sample.tenant.userclouds.com/invite/send'
plexClient := plex.NewClient("https://sample.tenant.userclouds.com")
inviteReq := plex.SendInviteRequest{
InviteeEmail: "alice@contoso.com",
InviterUserID: "68d69e31-6423-43e7-8e1b-c44956360410",
ClientID: "5f107e226353791560f93164a09f7e0f",
State: "n9ftgCrrLNQ7sfxnnFmNcabEn8hFvAypP6Hu625WtBk",
RedirectURL: "https://contoso.com/invitecallback",
InviteText: "Alice is inviting you to join the group",
Expires: time.Now().UTC().Add(time.Hour * 24 * 30),
}
if err := plexClient.SendInvite(ctx, inviteReq); err != nil {
...
}
Plex supports inviting users to join a tenant, which serves 3 main purposes:
- Reduce friction for new users to sign-up & sign-in to your application by emailing them a magic link which takes them to the right place to sign up or sign in to an existing account.
- Limit new user sign-ups for an application to only users who have been invited. NOTE: invites may still be useful even if a tenant allows new user sign ups.
- Perform special one-time actions (e.g. add user to a group, confer new permissions, etc) associated with the invite.
Once a user acts on an invite and either signs up for a new account or signs in with an existing account, their user agent will be redirected to the callback URL provided in the request which allows your application to perform one-time actions for a newly invited user.
Request
Parameter | Type | Required? | Description |
---|---|---|---|
invitee_email | string | yes | Email address of user to be invited |
inviter_user_id | string | yes | User ID of the inviting user. It's a string, not a UUID, because the format depends on the underlying IDP (UUIDs for UserClouds, strings for others) |
client_id | string | yes | Client ID of the app within the tenant that the invite is intended for (though the user will be invited to the overall tenant user pool, specific client IDs may have different rules) |
state | string | yes | An application-defined value used for 2 purpose: encode application state/context for a request, and to prevent CSRF attacks. See OAuth Security Topics for details. |
redirect_uri | string | yes | A URL to your application where the user agent will be redirected after successfully accepting the invite. Must use https:// for production web apps, or a mobile custom scheme for mobile apps. Can use http:// for localhost and development tenants. |
invite_text | string | no | An optional tag line included in the invite to provide app-specific or custom context. |
expires | datetime | no | An optional expiration time for the invite. If not specified, defaults to 1 week. |
Response
HTTP/1.1 204 No Content
204 No Content
on success, or one of the following errors:
Code | Reason |
---|---|
400 | TODO |
401 | TODO |
Authorization
List Objects
GET /authz/objects HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'GET' \
'https://sample.tenant.userclouds.com/objects/'
c := authz.NewClient("https://sample.tenant.userclouds.com")
objs, err := c.ListObjects(ctx)
fmt.Printf("Object count: %d, objects: %v", len(objs), objs
Lists all objects in the AuthZ system for a given tenant.
Request
Parameter | Type | Required | Description |
---|---|---|---|
name | query | optional | Alias of the object to filter on. Must currently be specified with 'type_id'. |
type_id | query | optional | Type ID of the object type to filter on. Must currently be specified with 'name'. |
TODO: rename 'name' to 'alias' for consistency.
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
[{
"id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"alias":"some widget",
"type_id":"f5bce640-f866-4464-af1a-9e7474c4a90c"
},{
"id":"1f4b0b03-4af0-409a-9769-50ce59526956",
"created":"2022-05-07T19:25:17.435965Z",
"updated":"2022-05-07T19:25:17.435965Z",
"deleted":"0001-01-01T00:00:00Z",
"alias":"a wodget",
"type_id":"2476b545-9d7b-4606-aa14-491add99213c"
}]
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the object retrieved. |
created | datetime | Timestamp of the object's creation. |
updated | datetime | Timestamp of the object's most recent update. |
deleted | datetime | Timestamp of the object's deletion, or the "0" timestamp if alive. |
alias | string | Application-provided human-readable alias for the object. |
type_id | UUIDv4 | ID of the object type. |
Get Object
GET /authz/objects/60b2f286-f051-444f-9b08-4b67129dcb7b HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'GET' \
'https://sample.tenant.userclouds.com/objects/60b2f286-f051-444f-9b08-4b67129dcb7b'
c := authz.NewClient("https://sample.tenant.userclouds.com")
obj, err := c.GetObject(ctx, uuid.Must(uuid.FromString('60b2f286-f051-444f-9b08-4b67129dcb7b')))
fmt.Printf("Object type ID: %s, alias: %s", obj.TypeID, obj.Alias)
Retrieves a single AuthZ object by ID. If the ID provided is that of a User in the IDP, it rerturns an object representing the user.
Request
Parameter | Type | Required | Description |
---|---|---|---|
/objects/{id} | UUIDv4 (in path) | yes | ID of the object to get. |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"alias":"some widget",
"type_id":"f5bce640-f866-4464-af1a-9e7474c4a90c"
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the object retrieved. |
created | datetime | Timestamp of the object's creation. |
updated | datetime | Timestamp of the object's most recent update. |
deleted | datetime | Timestamp of the object's deletion, or the "0" timestamp if alive. |
alias | string | Application-provided human-readable alias for the object. |
type_id | UUIDv4 | ID of the object type. |
Create Object
POST /authz/objecttypes HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
{
"id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"type_id":"8775116f-86cd-4f44-8023-e3108a901abd",
"alias":"blue widget",
}
curl -X 'POST' \
-H 'Content-Type: application/json' \
-d '{"id":"60b2f286-f051-444f-9b08-4b67129dcb7b", type_id":"8775116f-86cd-4f44-8023-e3108a901abd", "alias":"blue widget"}' \
'https://sample.tenant.userclouds.com/authz/objects'
c := authz.NewClient("https://sample.tenant.userclouds.com")
object, err := c.CreateObject(ctx, uuid.Must(uuid.NewV4()), uuid.Must(uuid.FromString("8775116f-86cd-4f44-8023-e3108a901abd")), "blue widget")
Creates an object with a given ID, Type ID, and Alias. See Create Object Type for details on how to create an object type.
Request
Parameter | Type | Required | Description |
---|---|---|---|
id | UUIDv4 | yes | ID of the newly created object. |
type_id | UUIDv4 | yes | Existing Type ID of the object's type. |
alias | string | yes | Application-provided human-readable alias for the object |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"alias":"some widget",
"type_id":"f5bce640-f866-4464-af1a-9e7474c4a90c"
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the newly created object. |
created | datetime | Timestamp of the object's creation. |
updated | datetime | Timestamp of the object's most recent update. |
deleted | datetime | Timestamp of the object's deletion, or the "0" timestamp if alive. |
type_id | UUIDv4 | Existing Type ID of the object's type. |
alias | string | Application-provided human-readable alias for the object |
Update Object
POST /authz/objects HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
{
"id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"type_id":"8775116f-86cd-4f44-8023-e3108a901abd",
"alias":"new alias",
}
curl -X 'POST' \
-H 'Content-Type: application/json' \
-d '{"id":"60b2f286-f051-444f-9b08-4b67129dcb7b", type_id":"8775116f-86cd-4f44-8023-e3108a901abd", "alias":"new alias"}' \
'https://sample.tenant.userclouds.com/authz/objects'
c := authz.NewClient("https://sample.tenant.userclouds.com")
// NOTE: separate client method for update coming soon
object, err := c.CreateObject(ctx, uuid.FromStringOrNil("60b69666-4a8a-4eb3-94dd-621298fb365d"), uuid.FromStringOrNil("8775116f-86cd-4f44-8023-e3108a901abd"), "new alias")
Update an object with a given ID, Type ID, and Alias. The Type ID cannot be changed in an Update operation, because doing so would invalidate existing edges (which are strongly typed).
Request
Parameter | Type | Required | Description |
---|---|---|---|
id | UUIDv4 | yes | ID of the existing object. |
type_id | UUIDv4 | yes | Existing Type ID of the object's type. Must not change from original creation. |
alias | string | yes | Application-provided human-readable alias for the object |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"alias":"some widget",
"type_id":"f5bce640-f866-4464-af1a-9e7474c4a90c"
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the existing created object. |
created | datetime | Timestamp of the object's creation. |
updated | datetime | Timestamp of the object's most recent update. |
deleted | datetime | Timestamp of the object's deletion, or the "0" timestamp if alive. |
type_id | UUIDv4 | Existing Type ID of the object's type. |
alias | string | Application-provided human-readable alias for the object |
Delete Object
DELETE /authz/objects/60b2f286-f051-444f-9b08-4b67129dcb7b HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'DELETE' \
'https://sample.tenant.userclouds.com/authz/objects/60b2f286-f051-444f-9b08-4b67129dcb7b'
c := authz.NewClient("https://sample.tenant.userclouds.com")
err := c.DeleteObject(ctx, uuid.Must(uuid.FromString('60b2f286-f051-444f-9b08-4b67129dcb7b')))
Delete an object with the given ID.
Request
Parameter | Type | Required | Description |
---|---|---|---|
/objects/{id} | UUIDv4 (in path) | yes | ID of the object to delete. |
Response
HTTP/1.1 204 No Content
204 No Content
on success, or one of the following errors:
Code | Reason |
---|---|
401 | No credentials or invalid credentials provided |
404 | Object with ID not found |
500 | Internal error occurred processing the request |
List Edges On Object
GET /authz/objects/60b2f286-f051-444f-9b08-4b67129dcb7b/edges HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'GET' \
'https://sample.tenant.userclouds.com/objects/60b2f286-f051-444f-9b08-4b67129dcb7b/edges'
c := authz.NewClient("https://sample.tenant.userclouds.com")
err := c.ListEdges(ctx, uuid.Must(uuid.FromString('60b2f286-f051-444f-9b08-4b67129dcb7b')))
List all incoming and outgoing edges on an object (i.e. all edges where the provided object is a source or target).
Request
Parameter | Type | Required | Description |
---|---|---|---|
/objects/{id} | UUIDv4 (in path) | yes | ID of the object to list edges for. |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
[
{
"id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"edge_type_id":"79c68abe-6227-4a2f-a2eb-6d7bc8e86766",
"source_object_id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"target_object_id":"70a8c988-265a-494d-81f5-43bc4bbd0df8"
}
]
200 OK
on success, or one of the following errors:
Code | Reason |
---|---|
401 | No credentials or invalid credentials provided |
404 | Object with ID not found |
500 | Internal error occurred processing the request |
List Edges Between Objects
GET /authz/edges?source_object_id=60b2f286-f051-444f-9b08-4b67129dcb7b&target_object_id=70a8c988-265a-494d-81f5-43bc4bbd0df8 HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'GET' \
'https://sample.tenant.userclouds.com/authz/edges?source_object_id=60b2f286-f051-444f-9b08-4b67129dcb7b&target_object_id=70a8c988-265a-494d-81f5-43bc4bbd0df8'
c := authz.NewClient("https://sample.tenant.userclouds.com")
err := c.ListEdgesBetweenObjects(ctx,
uuid.Must(uuid.FromString('60b2f286-f051-444f-9b08-4b67129dcb7b')),
uuid.Must(uuid.FromString('70a8c988-265a-494d-81f5-43bc4bbd0df8')))
List all edges between two objects.
Request
Parameter | Type | Required | Description |
---|---|---|---|
source_object_id | UUIDv4 | yes | ID of the source object to list edges for. |
target_object_id | UUIDv4 | yes | ID of the source object to list edges for. |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
[
{
"id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"edge_type_id":"79c68abe-6227-4a2f-a2eb-6d7bc8e86766",
"source_object_id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"target_object_id":"70a8c988-265a-494d-81f5-43bc4bbd0df8"
}
]
200 OK
on success, or one of the following errors:
Code | Reason |
---|---|
401 | No credentials or invalid credentials provided |
404 | Object with ID not found |
500 | Internal error occurred processing the request |
Get Edge
GET /authz/edges/60b2f286-f051-444f-9b08-4b67129dcb7b HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'GET' \
'https://sample.tenant.userclouds.com/authz/edges/60b2f286-f051-444f-9b08-4b67129dcb7b'
c := authz.NewClient("https://sample.tenant.userclouds.com")
err := c.GetEdge(ctx, uuid.Must(uuid.FromString('60b2f286-f051-444f-9b08-4b67129dcb7b')))
Describe an edge given its edge ID.
Request
Parameter | Type | Required | Description |
---|---|---|---|
/edges/[ID] | UUIDv4 (in path) | yes | ID of the edge |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
[
{
"id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"edge_type_id":"79c68abe-6227-4a2f-a2eb-6d7bc8e86766",
"source_object_id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"target_object_id":"70a8c988-265a-494d-81f5-43bc4bbd0df8"
}
]
200 OK
on success, or one of the following errors:
Code | Reason |
---|---|
401 | No credentials or invalid credentials provided |
404 | Edge with ID not found |
500 | Internal error occurred processing the request |
Create Edge
POST /authz/edges HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
{
"id":"8775116f-86cd-4f44-8023-e3108a901abd",
"source_object_id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"target_object_id":"70a8c988-265a-494d-81f5-43bc4bbd0df8",
"edge_type_id":"79c68abe-6227-4a2f-a2eb-6d7bc8e86766"
}
curl -X 'POST' \
-H 'Content-Type: application/json' \
-d '{"id":"8775116f-86cd-4f44-8023-e3108a901abd","source_object_id":"60b2f286-f051-444f-9b08-4b67129dcb7b","target_object_id":"70a8c988-265a-494d-81f5-43bc4bbd0df8","edge_type_id":"79c68abe-6227-4a2f-a2eb-6d7bc8e86766"}' \
'https://sample.tenant.userclouds.com/authz/edges'
c := authz.NewClient("https://sample.tenant.userclouds.com")
objectType, err := c.CreateEdge(ctx,
uuid.Must(uuid.NewV4()),
uuid.Must(uuid.FromString("60b2f286-f051-444f-9b08-4b67129dcb7b")),
uuid.Must(uuid.FromString("70a8c988-265a-494d-81f5-43bc4bbd0df8")),
uuid.Must(uuid.FromString("79c68abe-6227-4a2f-a2eb-6d7bc8e86766")))
Create a directed edge of a given type between a specified 'source' and 'target' objects.
Request
Parameter | Type | Required | Description |
---|---|---|---|
id | UUIDv4 | yes | ID of the newly created edge. |
source_object_id | UUIDv4 | yes | ID of the source object. |
target_object_id | UUIDv4 | yes | ID of the target object. |
edge_type_id | UUIDv4 | yes | ID of the edge type. |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"8775116f-86cd-4f44-8023-e3108a901abd",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"source_object_id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"target_object_id":"70a8c988-265a-494d-81f5-43bc4bbd0df8",
"edge_type_id":"79c68abe-6227-4a2f-a2eb-6d7bc8e86766"
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the newly created object. |
created | datetime | Timestamp of the object type's creation. |
updated | datetime | Timestamp of the object type's most recent update. |
deleted | datetime | Timestamp of the object type's deletion, or the "0" timestamp if alive. |
source_object_id | UUIDv4 | ID of the source object. |
target_object_id | UUIDv4 | ID of the target object. |
edge_type_id | UUIDv4 | ID of the edge type. |
Delete Edge
DELETE /authz/edges/60b2f286-f051-444f-9b08-4b67129dcb7b HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'DELETE' \
'https://sample.tenant.userclouds.com/authz/edges/60b2f286-f051-444f-9b08-4b67129dcb7b'
c := authz.NewClient("https://sample.tenant.userclouds.com")
err := c.DeleteEdge(ctx, uuid.Must(uuid.FromString('60b2f286-f051-444f-9b08-4b67129dcb7b')))
Delete an edge by its ID.
Request
Parameter | Type | Required | Description |
---|---|---|---|
/edges/{id} | UUIDv4 (in path) | yes | ID of the object to delete. |
Response
HTTP/1.1 204 No Content
204 No Content
on success, or one of the following errors:
Code | Reason |
---|---|
401 | No credentials or invalid credentials provided |
404 | Edge with ID not found |
500 | Internal error occurred processing the request |
List Object Types
GET /authz/objecttypes HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'GET' \
'https://sample.tenant.userclouds.com/authz/objecttypes'
c := authz.NewClient("https://sample.tenant.userclouds.com")
objectTypes, err := c.ListObjectTypes(ctx)
Lists all registered object types for this tenant.
Request
No parameters
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
[{
"id":"1634c490-20dc-4ded-abd1-9d2cafd8f08a",
"created":"2022-05-06T20:58:46.978552Z",
"updated":"2022-05-06T20:58:46.978552Z",
"deleted":"0001-01-01T00:00:00Z",
"type_name":"widget"
},{
"id":"1bf2b775-e521-41d3-8b7e-78e89427e6fe",
"created":"2022-03-30T03:10:28.169178Z",
"updated":"2022-04-30T21:16:01.763461Z",
"deleted":"0001-01-01T00:00:00Z",
"type_name":"_user"
},{
"id":"f5bce640-f866-4464-af1a-9e7474c4a90c",
"created":"2022-03-30T03:10:28.132552Z",
"updated":"2022-04-30T21:16:01.741283Z",
"deleted":"0001-01-01T00:00:00Z",
"type_name":"_group"
}]
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the object type. |
created | datetime | Timestamp of the object type's creation. |
updated | datetime | Timestamp of the object type's most recent update. |
deleted | datetime | Timestamp of the object type's deletion, or the "0" timestamp if alive. |
type_name | string | Application-provided human-readable name for the object type |
Get Object Type
GET /authz/objecttypes/60b69666-4a8a-4eb3-94dd-621298fb365d HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'GET' \
'https://sample.tenant.userclouds.com/authz/objecttypes/60b69666-4a8a-4eb3-94dd-621298fb365d'
c := authz.NewClient("https://sample.tenant.userclouds.com")
edgeType, err := c.GetObjectType(ctx, uuid.FromStringOrNil("60b69666-4a8a-4eb3-94dd-621298fb365d"))
Gets the definition of a single object type.
Request
Parameter | Type | Required | Description |
---|---|---|---|
/objecttypes/{id} | UUIDv4 (in path) | yes | ID of the object type to get. |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"069d6e9a-f31f-4514-a37f-78e8fdace9e0",
"created":"2022-05-07T01:34:57.405258Z",
"updated":"2022-05-07T01:34:57.405258Z",
"deleted":"0001-01-01T00:00:00Z",
"type_name":"widget_owner"
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the edge type. |
created | datetime | Timestamp of the edge type's creation. |
updated | datetime | Timestamp of the edge type's most recent update. |
deleted | datetime | Timestamp of the edge type's deletion, or the "0" timestamp if alive. |
type_name | string | Application-provided human-readable name for the edge type. |
Create Object Type
POST /authz/objecttypes HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
{
"id":"8775116f-86cd-4f44-8023-e3108a901abd",
"type_name":"widget",
}
curl -X 'POST' \
-H 'Content-Type: application/json' \
-d '{"id":"8775116f-86cd-4f44-8023-e3108a901abd","type_name":"widget"}' \
'https://sample.tenant.userclouds.com/authz/objecttypes'
c := authz.NewClient("https://sample.tenant.userclouds.com")
objectType, err := c.CreateObjectType(ctx, uuid.Must(uuid.NewV4()), "widget")
Creates a new object type.
Request
Parameter | Type | Required | Description |
---|---|---|---|
id | UUIDv4 | yes | ID of the newly created object. |
type_name | string | yes | Application-provided human-readable name for the object type. |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"type_name":"widget",
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the newly created object. |
created | datetime | Timestamp of the object type's creation. |
updated | datetime | Timestamp of the object type's most recent update. |
deleted | datetime | Timestamp of the object type's deletion, or the "0" timestamp if alive. |
type_name | string | Application-provided human-readable name for the object type. |
Delete Object Type
DELETE /authz/objecttypes/60b2f286-f051-444f-9b08-4b67129dcb7b HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'DELETE' \
'https://sample.tenant.userclouds.com/objecttypes/60b2f286-f051-444f-9b08-4b67129dcb7b'
c := authz.NewClient("https://sample.tenant.userclouds.com")
err := c.DeleteObjectType(ctx, uuid.FromStringOrNil("60b2f286-f051-444f-9b08-4b67129dcb7b"))
Delete a previously-registered object type with a given ID.
Request
Parameter | Type | Required | Description |
---|---|---|---|
/objecttypes/{id} | UUIDv4 (in path) | yes | ID of the object type to delete. |
Response
HTTP/1.1 204 No Content
204 No Content
on success, or one of the following errors:
Code | Reason |
---|---|
401 | No credentials or invalid credentials provided |
404 | Object with ID not found |
500 | Internal error occurred processing the request |
List Edge Types
GET /authz/edgetypes HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'GET' \
'https://sample.tenant.userclouds.com/authz/edgetypes'
c := authz.NewClient("https://sample.tenant.userclouds.com")
edgeTypes, err := c.ListEdgeTypes(ctx)
Lists all registered edge types for this tenant.
Request
No parameters
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
[{
"id":"069d6e9a-f31f-4514-a37f-78e8fdace9e0",
"created":"2022-05-07T01:34:57.405258Z",
"updated":"2022-05-07T01:34:57.405258Z",
"deleted":"0001-01-01T00:00:00Z",
"type_name":"widget_owner",
"source_object_type_id":"2476b545-9d7b-4606-aa14-491add99213c",
"target_object_type_id":"1bf2b775-e521-41d3-8b7e-78e89427e6fe"
},{
"id":"1eec16ec-6130-4f9e-a51f-21bc19b20d8f",
"created":"2022-03-30T03:10:28.301931Z",
"updated":"2022-04-30T21:16:01.844554Z",
"deleted":"0001-01-01T00:00:00Z",
"type_name":"_member",
"source_object_type_id":"f5bce640-f866-4464-af1a-9e7474c4a90c",
"target_object_type_id":"1bf2b775-e521-41d3-8b7e-78e89427e6fe"
},{
"id":"60b69666-4a8a-4eb3-94dd-621298fb365d",
"created":"2022-03-30T03:10:28.269905Z",
"updated":"2022-04-30T21:16:01.813831Z",
"deleted":"0001-01-01T00:00:00Z",
"type_name":"_admin",
"source_object_type_id":"f5bce640-f866-4464-af1a-9e7474c4a90c",
"target_object_type_id":"1bf2b775-e521-41d3-8b7e-78e89427e6fe"
}]
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the edge type. |
created | datetime | Timestamp of the edge type's creation. |
updated | datetime | Timestamp of the edge type's most recent update. |
deleted | datetime | Timestamp of the edge type's deletion, or the "0" timestamp if alive. |
type_name | string | Application-provided human-readable name for the edge type. |
Get Edge Type
GET /authz/edgetypes/60b69666-4a8a-4eb3-94dd-621298fb365d HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'GET' \
'https://sample.tenant.userclouds.com/authz/edgetypes/60b69666-4a8a-4eb3-94dd-621298fb365d'
c := authz.NewClient("https://sample.tenant.userclouds.com")
edgeType, err := c.GetEdgeType(ctx, uuid.FromStringOrNil("60b69666-4a8a-4eb3-94dd-621298fb365d"))
Gets the definition of a single edge type.
Request
Parameter | Type | Required | Description |
---|---|---|---|
/edgetypes/{id} | UUIDv4 (in path) | yes | ID of the edge type to get. |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"069d6e9a-f31f-4514-a37f-78e8fdace9e0",
"created":"2022-05-07T01:34:57.405258Z",
"updated":"2022-05-07T01:34:57.405258Z",
"deleted":"0001-01-01T00:00:00Z",
"type_name":"widget_owner",
"source_object_type_id":"2476b545-9d7b-4606-aa14-491add99213c",
"target_object_type_id":"1bf2b775-e521-41d3-8b7e-78e89427e6fe"
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the edge type. |
created | datetime | Timestamp of the edge type's creation. |
updated | datetime | Timestamp of the edge type's most recent update. |
deleted | datetime | Timestamp of the edge type's deletion, or the "0" timestamp if alive. |
type_name | string | Application-provided human-readable name for the edge type. |
Create Edge Type
POST /authz/edgetypes HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
{
"id":"8775116f-86cd-4f44-8023-e3108a901abd",
"type_name":"invitee",
"source_object_type_id":"f5bce640-f866-4464-af1a-9e7474c4a90c",
"target_object_type_id":"1bf2b775-e521-41d3-8b7e-78e89427e6fe"
}
curl -X 'POST' \
-H 'Content-Type: application/json' \
-d '{"id":"8775116f-86cd-4f44-8023-e3108a901abd","type_name":"invitee","source_object_type_id":"f5bce640-f866-4464-af1a-9e7474c4a90c","target_object_type_id":"1bf2b775-e521-41d3-8b7e-78e89427e6fe"}' \
'https://sample.tenant.userclouds.com/authz/edgetypes'
c := authz.NewClient("https://sample.tenant.userclouds.com")
edgeType, err := c.CreateEdgeType(ctx, uuid.Must(uuid.NewV4()), uuid.Must(uuid.FromString('f5bce640-f866-4464-af1a-9e7474c4a90c')), uuid.Must(uuid.FromString('1bf2b775-e521-41d3-8b7e-78e89427e6fe')), "invitee")
Creates a new edge (relationship) type.
Request
Parameter | Type | Required | Description |
---|---|---|---|
id | UUIDv4 | yes | ID of the newly created edge type. |
type_name | string | yes | Application-provided human-readable name for the edge (relationship) type. |
source_object_id | UUIDv4 | yes | Object Type ID to enforce for the "source" / "from" object for edges of this edge type. |
target_object_id | UUIDv4 | yes | Object Type ID to enforce for the "target" / "to" object for edges of this edge type. |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"type_name":"invitee",
"source_object_type_id":"f5bce640-f866-4464-af1a-9e7474c4a90c",
"target_object_type_id":"1bf2b775-e521-41d3-8b7e-78e89427e6fe"
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the newly created edge type. |
created | datetime | Timestamp of the object type's creation. |
updated | datetime | Timestamp of the object type's most recent update. |
deleted | datetime | Timestamp of the object type's deletion, or the "0" timestamp if alive. |
type_name | string | Application-provided human-readable name for the edge type |
source_object_id | UUIDv4 | Object Type ID to enforce for the "source" / "from" object for edges of this edge type. |
target_object_id | UUIDv4 | Object Type ID to enforce for the "target" / "to" object for edges of this edge type. |
Delete Edge Type
DELETE /authz/edgetypes/60b2f286-f051-444f-9b08-4b67129dcb7b HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'DELETE' \
'https://sample.tenant.userclouds.com/edgetypes/60b2f286-f051-444f-9b08-4b67129dcb7b'
c := authz.NewClient("https://sample.tenant.userclouds.com")
err := c.DeleteObjectType(ctx, uuid.FromStringOrNil("60b69666-4a8a-4eb3-94dd-621298fb365d"))
Delete a previously-registered edge type with a given ID.
Request
Parameter | Type | Required | Description |
---|---|---|---|
/edgetypes/{id} | UUIDv4 (in path) | yes | ID of the object type to delete. |
Response
HTTP/1.1 204 No Content
204 No Content
on success, or one of the following errors:
Code | Reason |
---|---|
401 | No credentials or invalid credentials provided |
404 | Object with ID not found |
500 | Internal error occurred processing the request |
User Data Vault
Intro
Vault is a centralized data store for sensitive information such as PII combined together with a set of per-use accessor methods that describe the policies for accessing that data. Vault is meant to contain the only long lived copy of the data and other services/systems obtain data for it for a particular purpose and delete it once that purpose is complete. Vault is designed to improve privacy and security of data regardless of the stage of the compliance program. It helps the user both achieve more with minimal additional work today and provides continuous work savings through the lifetime of the technical systems. Vault can be gradually adopted for particular data types, or particular subsystems providing immediate benefits.
Instead of using a generic API/language for accessing data as is state of the art today, Vault encourages the user to define a per use custom accessor for each particular use of data. Most of the work to define the custom accessor is done by the system so that the developer doesn't have to do much more than they would to write a custom query against a generic API. Optionally additional work can be performed at definition time of the customer accessor depending on the company's security/privacy program such as associating it with a product/feature, referencing a document generated by an approval process, or attaching precise access policies. Regardless of optional work upfront each use of data can be audited, turned off, constrained without impacting other uses, or later labeled with additional documentation.
Vault includes a set of adapters to allow turn-key integrations with best in class third party services. These adapters (depending on the service being integrated) can remove, mask, tokenize, or make less precise the literal data flowing in the third party service without affecting operation of the service. Vault will help you get to a place where with a single click in the UI you can determine which data is used by product/feature for what purpose, which third party systems are involved in the operation of product/feature, and how the data involved is protected.
Configuration Concepts
The system is first configured by describing what columns are going to be in the user table and how they will be stored. Then the you describe how the data can be accessed and by who. You can add new accessor definitions as you need to use data for new purposes.
Three are three separate sets of APIs:
Management - the APIs for configuring and maintaining the user store and associated policies Operations - the APIs used for online, offline and adapter access to the user data Audit - the APIs used for compliance purposes to verify, confirm correctness and integrate with internal processes such as approval flows and documentation
User store management APIs can be thought as a set of configuration files:
User store column definition file (What is stored in the user data store ?) - this file describes which columns are present in the data store, what type of data they contain, where the data should be stored, how the data should be encrypted, how the data relates to other columns and policies that should apply to all accesses
User store CRUD definition file (How can stored data be accessed ?) - this file describes APIs for accessing data for both online and offline flows. It includes a policy describing who should be able to data, how the data should be transformed prior to being returned and how the access should be documented. It covers both bulk and individual operations.
User store adapters definition file (Which integrations with other services are enabled ?) - this file describes which adapters are enabled for the data store and how they are configured. Adapters use the basic CRUD operations enabled on the data store but contain extra logic and configuration for common workflows. Adapters may expose extra APIs such as AWS/GCP lambda functions or web endpoints to match the interface of the third party service.
The changes to configuration can be made through UserClouds console requiring no coding, through UserClouds API, or through bulk upload of the new configuration file. Regardless, each configuration change is subject to the same approval flow and is recorded for audit purposes. Not all configuration changes are reversible without data loss so testing configuration changes in your development environment prior to production deployment is best practice
From the client side the user store can be expressed in a SQL, GraphQL or another preferred data fetching language via one of our SDKs or a custom SDK for your use case. This allows the client code to be written in a way that is agnostic to the infrastructure being used for storing user data or for ease of migration of existing code to User Data Vault.
Column Configuration
Describe sample user store in GraphQL
type User {
id: String! @ocolumn id
name: String! @column name
address: [Address!]! @column address
phone: String! @column phone
classes: [String!]! @column classes
}
enum AddressType {
HOME
OFFICE
OTHER
}
type Address {
type: AddressType! @column composite
street: String! @column composite
houseNumber: Int @column composite
zip: Int @column composite
}
type Query {
user(areaCode: String!): User
}
Describe sample user store in SQL
CREATE TABLE Users (
id UUID NOT NULL,
name VARCHAR(255) NOT NULL,
phone VARCHAR(255) NOT NULL,
address JSON NOT NULL,
classes JSON NOT NULL
) ENGINE=USERCLOUDS;
Each column in the user data store has the following configuration fields:
- Name - name of the column. Has to be distinct from other columns
- Primitive DataType - the type of data stored in the column - string, number, etc
- Logical Data Type - the type of data represented by the column - “First Name”, “Phone Number”, “Address”, etc. Either predefined types can be used or new type can be declared
- Purpose - reference to the purpose for which data was collected. Either predefined purposes can be used or new purposes can be declared
- Geo Distribution Policy [optional] - describes if the column should be stored in data centers in the user’s country/region, if it should be cached centrally and how the cache should expire. By default the columns are all stored in the same data center in the region you selected.
- Encryption Policy [optional] - describes if the column should be encrypted by a key you provide, by a key stored in another column. By default all columns are encrypted at rest by a per application key.
- Federation Policy [optional] - describes if the column should be stored on the user's device, the type of authentication action required to retrieve it (such as explicit user approval), duration of approved session, and caching policy. If you want to apply federation policy to your column please email support@userclouds.com
- Global Access Policy [optional] - describes access policy that should apply to every access to the column. This policy will be applied before the policy for individual CRUD API
The columns are limited in size and are not meant for storing bulk data. Instead you should store metadata, encryption keys and references to the bulk data in another store.
The columns can be defined via UserClouds console, CRUD API for columns or bulk updated via file upload. Column deletion doesn’t result in data deletion - instead the column is marked as deleted and can be removed via a separate operation.
There is a set of predefined columns that can’t be deleted:
- UserID - this column contains a GUID representing a user id issued by UserClouds on account creation. This column’s value is immutable.
Create Column
POST /userstore/config/columns HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
{
"id":"8775116f-86cd-4f44-8023-e3108a901abd",
"column_name":"FirstName",
"primitive_type":"string",
"logical_type":"Name-First",
"purpose":"Product_Improvement, Integrity, Product_Operation",
"global_access_policy":"f5bce640-f866-4464-af1a-9e7474c4a90c"
}
curl -X 'POST' \
-H 'Content-Type: application/json' \
-d '{"id":"8775116f-86cd-4f44-8023-e3108a901abd","column_name":"FirstName", "primitive_type":"string", "logical_type":"Name-First",
"purpose":"Product_Improvement, Integrity, Product_Operation","global_access_policy":"f5bce640-f866-4464-af1a-9e7474c4a90c"' \
'https://sample.tenant.userclouds.com/userstore/config/columns'
c := userstore.NewClient("https://sample.tenant.userclouds.com")
edgeType, err := c.CreateColumn(ctx, uuid.Must(uuid.NewV4()), uuid.Must(uuid.FromString('f5bce640-f866-4464-af1a-9e7474c4a90c')), "FirstName", "string", "Name-First", "Product_Improvement, Integrity, Product_Operation")
Creates a new column in the datastore.
Request
Parameter | Type | Required | Description |
---|---|---|---|
id | UUIDv4 | yes | ID of the newly created column type. |
column_name | string | yes | Application-provided human-readable name for the column. |
primitive_type | string | yes | Currently "string", "integer" and "uuid" are supported |
logical_type | string | yes | One of the UserClouds defined types or "custom" |
purpose | string | yes | A comma separated list of purposes |
glo_access_policy_id | UUIDv4 | no | ID of a policy to base access policy to the data. |
geo_policy_id | UUIDv4 | no | ID of a policy to describe which regions the data should stored in |
enc_policy_id | UUIDv4 | no | ID of a policy to describe encryption method for the data |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"column_name":"FirstName",
"primitive_type":"string",
"logical_type":"Name-First",
"purpose":"Product_Improvement, Integrity, Product_Operation",
"global_access_policy":"f5bce640-f866-4464-af1a-9e7474c4a90c"
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the newly created column. |
created | datetime | Timestamp of the column's creation. |
updated | datetime | Timestamp of the columns's most recent update. |
deleted | datetime | Timestamp of the column's deletion, or the "0" timestamp if alive. |
column_name | string | Application-provided human-readable name for the column. |
primitive_type | string | Currently "string", "integer" and "uuid" are supported |
logical_type | string | One of the UserClouds defined types or "custom" |
purpose | string | A comma separated list of purposes |
glo_access_policy_id | UUIDv4 | ID of a policy to base access policy to the data. |
geo_policy_id | UUIDv4 | ID of a policy to describe which regions the data should stored in |
enc_policy_id | UUIDv4 | ID of a policy to describe encryption method for the data |
Get Column
GET /userstore/config/columns/8775116f-86cd-4f44-8023-e3108a901abd HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'GET' \
'https://sample.tenant.userclouds.com/userstore/config/columns/8775116f-86cd-4f44-8023-e3108a901abd'
c := userstore.NewClient("https://sample.tenant.userclouds.com")
edgeType, err := c.GetColumn(ctx, uuid.FromStringOrNil("8775116f-86cd-4f44-8023-e3108a901abd))
Gets an existing column's configuration by its id.
Request
Parameter | Type | Required | Description |
---|---|---|---|
/columns/{id} | UUIDv4 (in path) | yes | ID of the column to get. |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"8775116f-86cd-4f44-8023-e3108a901abd",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"column_name":"FirstName",
"primitive_type":"string",
"logical_type":"Name-First",
"purpose":"Product_Improvement, Integrity, Product_Operation",
"global_access_policy":"f5bce640-f866-4464-af1a-9e7474c4a90c"
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the newly created column. |
created | datetime | Timestamp of the column's creation. |
updated | datetime | Timestamp of the columns's most recent update. |
deleted | datetime | Timestamp of the column's deletion, or the "0" timestamp if alive. |
column_name | string | Application-provided human-readable name for the column. |
primitive_type | string | Currently "string", "integer" and "uuid" are supported |
logical_type | string | One of the UserClouds defined types or "custom" |
purpose | string | A comma separated list of purposes |
glo_access_policy_id | UUIDv4 | ID of a policy to base access policy to the data. |
geo_policy_id | UUIDv4 | ID of a policy to describe which regions the data should stored in |
enc_policy_id | UUIDv4 | ID of a policy to describe encryption method for the data |
Update Column
POST /userstore/config/columns/8775116f-86cd-4f44-8023-e3108a901abd HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
{
"id":"8775116f-86cd-4f44-8023-e3108a901abd",
"update":"purpose: Product_Improvement, Product_Operation",
}
curl -X 'POST' \
-H 'Content-Type: application/json' \
-d '{"id":"8775116f-86cd-4f44-8023-e3108a901abd",
"purpose":"Product_Improvement, Product_Operation"' \
'https://sample.tenant.userclouds.com/userstore/config/columns/8775116f-86cd-4f44-8023-e3108a901abd'
c := userstore.NewClient("https://sample.tenant.userclouds.com")
edgeType, err := c.UpdateColumn(ctx, uuid.Must(uuid.FromString('8775116f-86cd-4f44-8023-e3108a901abd')), "Purpose: Product_Improvement, Product_Operation")
Update a column with a given ID. Certain fields cannot be changed in an Update operation, once the column contains data. A column update may invalidate the accessors defined for it.
Request
Parameter | Type | Required | Description |
---|---|---|---|
id | UUIDv4 | yes | ID of the existing column. |
update | string | yes | Fields to be updated |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"8775116f-86cd-4f44-8023-e3108a901abd",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"column_name":"FirstName",
"primitive_type":"string",
"logical_type":"Name-First",
"purpose":"Product_Improvement, Integrity, Product_Operation",
"global_access_policy":"f5bce640-f866-4464-af1a-9e7474c4a90c"
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the updated created column. |
created | datetime | Timestamp of the column's creation. |
updated | datetime | Timestamp of the columns's most recent update. |
deleted | datetime | Timestamp of the column's deletion, or the "0" timestamp if alive. |
column_name | string | Application-provided human-readable name for the column. |
primitive_type | string | Currently "string", "integer" and "uuid" are supported |
logical_type | string | One of the UserClouds defined types or "custom" |
purpose | string | A comma separated list of purposes |
glo_access_policy_id | UUIDv4 | ID of a policy to base access policy to the data. |
geo_policy_id | UUIDv4 | ID of a policy to describe which regions the data should stored in |
enc_policy_id | UUIDv4 | ID of a policy to describe encryption method for the data |
Delete Column
DELETE /userstore/config/columns/60b2f286-f051-444f-9b08-4b67129dcb7b HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'DELETE' \
'https://sample.tenant.userclouds.com/userstore/config/columns/60b2f286-f051-444f-9b08-4b67129dcb7b'
c := userstore.NewClient("https://sample.tenant.userclouds.com")
err := c.DeleteColumn(ctx, uuid.FromStringOrNil("60b69666-4a8a-4eb3-94dd-621298fb365d"))
Delete a column with given id. Note that deleting the column doesn't result in data deletion, but in the data being immediately unavailable. To delete the data stored in the column, you need to trigger the garbage collection process on the column which will remove the data after a configurable retention period. Note that the minimum retention period is 72 hours for primary copy and 30 days for backups. This three stage process and delay is designed to protect your user data from mistakes or in case of account takeover.
Request
Parameter | Type | Required | Description |
---|---|---|---|
/columns/{id} | UUIDv4 (in path) | yes | ID of the column to delete. |
Response
HTTP/1.1 204 No Content
204 No Content
on success, or one of the following errors:
Code | Reason |
---|---|
401 | No credentials or invalid credentials provided |
404 | Column with ID not found |
500 | Internal error occurred processing the request |
CRUD Configuration
Describe the userstore in GraphQL
type User {
id: String! @ocolumn id
name: String! @column name
address: [Address!]! @column address
phone: String! @column phone
classes: [String!]! @column classes
}
enum AddressType {
HOME
OFFICE
OTHER
}
type Address {
type: AddressType! @column composite
street: String! @column composite
houseNumber: Int @column composite
zip: Int @column composite
}
Define the query method which maps to the accessor getusersforareacode
query GetUsersForAreaCode($ac: String!) @method getusersforareacode{
user(areaCode: $ac) {
name
address
}
}
GetUsersForAreaCode(“650”)
Describe the userstore in SQL
CREATE TABLE Users (
id UUID NOT NULL,
name VARCHAR(255) NOT NULL,
phone VARCHAR(255) NOT NULL,
address JSON NOT NULL,
classes JSON NOT NULL
) ENGINE=USERCLOUDS;
Define the stored procedure which maps to the accessor getusersforareacode
CREATE PROCEDURE GetUsersForAreaCode(
IN areaCode VARCHAR(255)
)
BEGIN
SELECT name, address
FROM User
WHERE phone LIKE areaCode
END
CALL GetUsersForAreaCode(‘650’)
Each individual CRUD API has the following properties:
- Name - name of the API. Has to be distinct per user store.
- Operation - one of CREATE/READ/UPDATE/DELETE
- Data Array [1..N]:
- Column Name - name of the column on which this API operates
- Selector Array [0..N]:
- Selector Expression - selector expression for filtering
- Access Policy - describes who should be allowed to access this API. Always includes a distinction between offline and online access. Usually includes authorization group membership check and data use purpose check for which this API is intended.
- Data Transform [optional] - only available for READ operation. This policy described how the data should be transformed prior to return. It can be returned as is, tokenized, made less precise by randomizing by a shift amount, or made partial. By default data is returned as is.
- Data Validation [optional] - only available for CREATE/UPDATE operations. This policy describes how the data should be validated before being accepted. By default data is verified to match the format of the primitive and logical data type specified for the column
- Approval Policy [optional] - describes if access requires out of phase approval (like a MFA code entry by an authorized individual) or special audit logging
- Product Boundary [optional] - is a set of paths (/Product/Platform/Feature/SubFeature) describing from which parts of the application this API can be called. It can be used together with UserClouds client SDK to maintain data use boundaries within applications that combine multiple user facing products (such as a marketplace and ads product) or data pipelines that serve those products. It can also be used for generating reports for which data is accessed by which feature.
- Documentation Reference [optional] - a reference to an internal document/artifact from the process used to approve this use of user data. This field can be made required in the global configuration or per column
Describe the userstore in GraphQL
type User {
name: String! @column name
address: [Address!]! @column address
phone: String! @column phone
classes: [String!]! @column classes
}
enum AddressType {
HOME
OFFICE
OTHER
}
type Address {
type: AddressType! @column composite
street: String! @column composite
houseNumber: Int @column composite
zip: Int @column composite
}
Define the query method which maps to the accessor getusersforareacode
type Query {
user(areaCode: String!): User
}
query GetUsersForAreaCode($ac: String!) @method getusersforareacode{
user(areaCode: $ac) {
name
address
}
}
GetUsersForAreaCode(“650”)
Each CRUD API can be expressed as a SQL or GraphQL query or another preferred data fetching language - see examples on the right. This allows the client code to be written in a way that is agnostic to the infrastructure being used for storing user data or for ease of migration of existing code to User Data Vault.
Create Accessor
POST /userstore/config/api HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
{
"id":"8775116f-86cd-4f44-8023-e3108a901abd",
"name":"GetUsersForAreaCode",
"operation":"READ",
"columns":["id", "name", "address"],
"selectors":["phone.contains"],
"access_policy":"f5bce640-f866-4464-af1a-9e7474c4a90c"
}
curl -X 'POST' \
-H 'Content-Type: application/json' \
-d '{"id":"8775116f-86cd-4f44-8023-e3108a901abd","name":"GetUsersForAreaCode", "operation":"READ", "columns":["id", "name", "address"], "selectors":["phone.contains"],
"access_policy":"f5bce640-f866-4464-af1a-9e7474c4a90c"' \
'https://sample.tenant.userclouds.com/userstore/config/api'
c := userstore.NewClient("https://sample.tenant.userclouds.com")
edgeType, err := c.CreateAPI(ctx, uuid.Must(uuid.NewV4()), "GetUsersForAreaCode", "READ",
["id", "name", "address"], "selectors":["phone.contains"],uuid.Must(uuid.FromString('f5bce640-f866-4464-af1a-9e7474c4a90c')))
Creates a new api to perform an operation on the datastore.
Request
Parameter | Type | Required | Description |
---|---|---|---|
id | UUIDv4 | yes | ID of the newly created api. |
name | string | yes | Application-provided human-readable name for the api. |
columns | string | yes | A comma separated list of column names |
selectors | string | no | A comma separated list of selectors names |
operation | enum | yes | Operation type CREATE/READ/UPDATE/DELETE |
access_policy_id | UUIDv4 | yes | ID of a policy to access policy to execute the operation. |
data_transform_id | UUIDv4 | no | ID of a transform to modify the return value(s). |
data_validator_id | UUIDv4 | no | ID of a transform to validate the input value(s). |
approval_policy_id | UUIDv4 | no | ID of a policy describing manual approval triggers |
product_path | string | no | A comma separate list of product paths |
doc_ref_id | UUIDv4 | no | ID of a document from privacy program |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"60b2f286-f051-444f-9b08-4b67129dcb7b",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"name":"GetUsersForAreaCode",
"operation":"READ",
"columns":"["id", "name", "address"]",
"selectors":["phone.contains"],
"access_policy":"f5bce640-f866-4464-af1a-9e7474c4a90c"
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the newly created api. |
created | datetime | Timestamp of the api's creation. |
updated | datetime | Timestamp of the api's most recent update. |
deleted | datetime | Timestamp of the api's deletion, or the "0" timestamp if alive. |
name | string | Application-provided human-readable name for the api. |
columns | string | A comma separated list of column names |
selectors | string | A comma separated list of selectors names |
operation | enum | Operation type CREATE/READ/UPDATE/DELETE |
access_policy_id | UUIDv4 | ID of a policy to access policy to execute the operation. |
data_transform_id | UUIDv4 | ID of a transform to modify the return value(s). |
data_validator_id | UUIDv4 | ID of a transform to validate the input value(s). |
approval_policy_id | UUIDv4 | ID of a policy describing manual approval triggers |
product_path | string | A comma separate list of product paths |
doc_ref_id | UUIDv4 | ID of a document from privacy program |
Get Accessor
GET /userstore/config/api/8775116f-86cd-4f44-8023-e3108a901abd HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'GET' \
'https://sample.tenant.userclouds.com/userstore/config/api/8775116f-86cd-4f44-8023-e3108a901abd'
c := userstore.NewClient("https://sample.tenant.userclouds.com")
edgeType, err := c.GetAPI(ctx, uuid.FromStringOrNil("8775116f-86cd-4f44-8023-e3108a901abd))
Gets an existing accessor's configuration by its id.
Request
Parameter | Type | Required | Description |
---|---|---|---|
/api/{id} | UUIDv4 (in path) | yes | ID of the accessor to get. |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"8775116f-86cd-4f44-8023-e3108a901abd",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"name":"GetUsersForAreaCode",
"operation":"READ",
"columns":"["id", "name", "address"]",
"selectors":["phone.contains"],
"access_policy":"f5bce640-f866-4464-af1a-9e7474c4a90c"
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the newly created api. |
created | datetime | Timestamp of the api's creation. |
updated | datetime | Timestamp of the api's most recent update. |
deleted | datetime | Timestamp of the api's deletion, or the "0" timestamp if alive. |
name | string | Application-provided human-readable name for the api. |
columns | string | A comma separated list of column names |
selectors | string | A comma separated list of selectors names |
operation | enum | Operation type CREATE/READ/UPDATE/DELETE |
access_policy_id | UUIDv4 | ID of a policy to access policy to execute the operation. |
data_transform_id | UUIDv4 | ID of a transform to modify the return value(s). |
data_validator_id | UUIDv4 | ID of a transform to validate the input value(s). |
approval_policy_id | UUIDv4 | ID of a policy describing manual approval triggers |
product_path | string | A comma separate list of product paths |
doc_ref_id | UUIDv4 | ID of a document from privacy program |
Update Accessor
POST /userstore/config/api/8775116f-86cd-4f44-8023-e3108a901abd HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
{
"id":"8775116f-86cd-4f44-8023-e3108a901abd",
"update" : "columns:[id, name, phone, address]",
}
curl -X 'POST' \
-H 'Content-Type: application/json' \
-d '{"id":"8775116f-86cd-4f44-8023-e3108a901abd", "update": "columns:[id, name, address]", ' \
'https://sample.tenant.userclouds.com/userstore/config/api'
c := userstore.NewClient("https://sample.tenant.userclouds.com")
edgeType, err := c.UpdateAPI(ctx, uuid.Must(uuid.FromString('8775116f-86cd-4f44-8023-e3108a901abd')),
"columns: [id, name, address]")
Update an accessor with a given ID. Name and ID are immutable.
Request
Parameter | Type | Required | Description |
---|---|---|---|
id | UUIDv4 | yes | ID of the existing accessor. |
update | string | yes | Fields to be updated |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"id":"8775116f-86cd-4f44-8023-e3108a901abd",
"created":"2022-03-28T21:43:36.099293Z",
"updated":"2022-03-28T21:43:36.099293Z",
"deleted":"0001-01-01T00:00:00Z",
"name":"GetUsersForAreaCode",
"operation":"READ",
"columns":"["id", "name", "address"]",
"selectors":["phone.contains"],
"access_policy":"f5bce640-f866-4464-af1a-9e7474c4a90c"
}
Parameter | Type | Description |
---|---|---|
id | UUIDv4 | ID of the updated api. |
created | datetime | Timestamp of the api's creation. |
updated | datetime | Timestamp of the api's most recent update. |
deleted | datetime | Timestamp of the api's deletion, or the "0" timestamp if alive. |
name | string | Application-provided human-readable name for the api. |
columns | string | A comma separated list of column names |
selectors | string | A comma separated list of selectors names |
operation | enum | Operation type CREATE/READ/UPDATE/DELETE |
access_policy_id | UUIDv4 | ID of a policy to access policy to execute the operation. |
data_transform_id | UUIDv4 | ID of a transform to modify the return value(s). |
data_validator_id | UUIDv4 | ID of a transform to validate the input value(s). |
approval_policy_id | UUIDv4 | ID of a policy describing manual approval triggers |
product_path | string | A comma separate list of product paths |
doc_ref_id | UUIDv4 | ID of a document from privacy program |
Delete Accessor
DELETE /userstore/config/api/60b2f286-f051-444f-9b08-4b67129dcb7b HTTP/1.1
Host: sample.tenant.userclouds.com
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
curl -X 'DELETE' \
'https://sample.tenant.userclouds.com/userstore/config/api/60b2f286-f051-444f-9b08-4b67129dcb7b'
c := userstore.NewClient("https://sample.tenant.userclouds.com")
err := c.DeleteAPI(ctx, uuid.FromStringOrNil("60b69666-4a8a-4eb3-94dd-621298fb365d"))
Delete a api with given id, which makes it immediately unavailable. Note that the api configuration is retained for 72 hours in case you need to restore it and for 30 days in backups. This two stage process and delay is designed to protect your api configuration from mistakes or in case of account takeover.
Request
Parameter | Type | Required | Description |
---|---|---|---|
/api/{id} | UUIDv4 (in path) | yes | ID of the accessor to delete. |
Response
HTTP/1.1 204 No Content
204 No Content
on success, or one of the following errors:
Code | Reason |
---|---|
401 | No credentials or invalid credentials provided |
404 | API with ID not found |
500 | Internal error occurred processing the request |
Execute Accessor
POST /userstore/api/8775116f-86cd-4f44-8023-e3108a901abd HTTP/1.1
Host: sample.tenant.userclouds.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...6PzZx3Y3FBuGc
{
"selectors":["650"],
"context:"{ "purpose":"Product Operation"}"
}
curl -X 'POST' \
-H 'Content-Type: application/json' \
-d '{"selectors":["650"], "context":"{ "purpose":"Product Operation"},' \
'https://sample.tenant.userclouds.com/userstore/api/8775116f-86cd-4f44-8023-e3108a901abd'
c := userstore.NewClient("https://sample.tenant.userclouds.com")
edgeType, err := c.CallAPI( "GetUsersForAreaCode", "650", '{ "purpose":"Product Operation"}')
Executes the accessor, performs the defined operation and returns any output if defined.
Request
Parameter | Type | Required | Description |
---|---|---|---|
selectors | string | no | A comma separated list of selectors inputs |
context | string | yes | Context for evaluating the access/approval policy |
access_policy_id | UUIDv4 | yes | ID of a policy to access policy to execute the operation. |
product_path | string | no | Product path |
Response
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
{
"output":"[ { name : name1, address: address1 }, {name: name2, address: address2}",
"state":"COMPLETE",
}
Parameter | Type | Description |
---|---|---|
output | JSON | Output of the operation if any |
state | enum | State of the execution - COMPLETE |
Or one of the following errors:
Code | Reason |
---|---|
401 | No credentials or invalid credentials provided |
404 | API with ID not found |
500 | Internal error occurred processing the request |
Policy Configuration
See Access Policy
Tokenizer
Tokenizer is available natively from inside the User Store, but also as a standalone API that can be called for singleton pieces of data, or in bulk.
Tokens are used to replace PII when the data needs to be transferred to secondary systems, but you want to retain control of what the data can be used for (and when) in a central policy store. Just before "sharing" the records, you tokenize important PII (using the Create Token API, or Lookup Token API if you want to reuse an already-created token for this value), and share that token instead. The Generation Policy controls how the token is generated (how much information to obscure or retain, formatting, etc).
When the time comes to use the data (eg. send an email), the user calls the Resolve Token API and the Access Policy controls whether or not the token can be resolved.
Generation Policies
type GenerationPolicy struct {
ID uuid.UUID
Function string
Parameters interface{}
}
Generation Policies control how a token is generated ... they range from the simplest built-in UUID
policy that naively replaces any given data with a unique identifier, to custom-written Javascript
that runs in a carefully-controlled sandbox.
In practice, a generation policy may be passed in-line to CreateToken()
, or it may be referenced
by ID (IDs may be included in in-line policies to "name" them, otherwise they will be automatically assigned);
if only an ID is passed, the policy will be looked up by ID. A CreateGenerationPolicy API is
also available for "offline" management.
A generation policy consists of a tuple of (ID, function, parameters)
id
- as described above
function
- a generator function with the signature func(data JSONValue, parameters JSONValue) (Token | error)
parameters
- a static JSON object (not containing PII) that is available at runtime, allowing you to parameterize
and reuse functions like "obfuscate all but the first X letters of these emails"
Access Policies
type AccessPolicy struct {
ID uuid.UUID
Function string
Parameters interface{}
}
Access Policies control token resolution down the line. They can be as simple as "allow any resolution with purpose 'security'" to complex Javascript evaluations including locations, credentials, etc.
Like generation policies, access policies can be passed in-line to CreateToken()
, or
they may be referenced by ID.
An access policy consists of a tuple of (ID, function, parameters)
id
- as described above
function
- a function with the signature func(token Token, parameters JSONValue, context JSONValue)
,
where context is passed in from the ResolveToken()
call.
parameters
- a static JSON object (not containing PII) that is available at runtime, allowing you to parameterize
and reuse functions like "allow access only from IP range X-Y"
Create Token API
func CreateToken(
data interface{},
attributes interface{},
gp GenerationPolicy,
ap AccessPolicy
) (*Token, error)
CreateToken creates a new token for a data NB: CreateToken will always generate a unique token for this data. If you want to reuse a token that was already generated, use LookupToken()
data
: a JSON-serializable object that is being tokenized (the PII)
attributes
: a JSON-serializable object that is stored alongside the data, but does not contain PII.
This is used for things like the InspectToken() API, as well as bulk DeleteToken() operations
(eg. delete all tokens associated with a given user_id)
gp
: a Generation Policy that controls how the token is generated
ap
: an Access Policy that controls under what conditions a token can be resolved
Lookup Token API
go LookupToken(
data interface{},
attributes interface{},
gp GenerationPolicy,
ap AccessPolicy,
) (*Token, error)
LookupToken
is just like CreateToken
, except that it only returns existing tokens that match across
the full set of parameters; if no token matches, an error is returned.
Resolve Token API
func ResolveToken(
token *Token,
context interface{},
) (interface{}, error)
ResolveToken takes a token and a resolution context (eg. the purpose for which the token is being resolved, by whom it is being resolved, etc), and either resolves the token or raises an error.
Inspect Token API
func InspectToken(
token *Token,
) (GenerationPolicy, AccessPolicy, Attributes, error)
InspectToken is primarily a debugging API that lets you query (but not resolve) a token.
Delete Token API
func DeleteToken(token *Token) error
func DeleteFromData(data interface{}) error
func DeleteByAttributes(attributes interface{}) error
DeleteToken
is actually a small collection of APIs that lets you delete tokens (break the link between PII
and downstream data) in various ways.
Batch APIs
Batch APIs are available for CreateToken
, LookupToken
and ResolveToken
.
Fundamentally a batch consists of an optional list of Generation Policies and
Access Policies that can be referenced in the list of objects (for CreateToken
and LookupToken
), followed by an ordered list of objects (either data, attribute
pairs, or tokens
).
Each object in the list may optionally be assigned an ID, which will be preserved in the response.
The response object consists of an order-preserved list of response objects, which include the ID (if
used in the request), a response object (Token
or data
), and/or an error for that particular object's operation.
Batch sizes are currently allowed up to 100 items but we expect we'll expand this much farther as we do more ETL integrations.
We currently don't support batches for InspectToken
(primarily for debugging) or DeleteToken
(because
attributes allows bulk deletion), but contact us if you need these.
Create Generation Policy API
func CreateGenerationPolicy(
gp GenerationPolicy,
) (uuid.UUID, error)
CreateGenerationPolicy
is a convenience wrapper around just inlining a generation policy on the first CreateToken
call.
Create Access Policy API
func CreateAccessPolicy(
ap AccessPolicy,
) (uuid.UUID, error)
CreateAccessPolicy
is a convenience wrapper around just inlining a access policy on the first CreateToken
call.