Configuring a Client via API
Make sure you obtain the following valid parameters from the Helm chart:
- AS_URI
- AS_ADMIN_URI
- AS_ADMIN_STATIC_TOKEN
Further instruction can be found at here
Overview
This page can be divided into two major sections + four sub sections as a fully functional Client (Service Provider) in FPX requires:
A Client entity which stores basic information of the Service Provider such as base_url or secret.
A ticket which is a collection of the following:
2.1 A purpose which describe what the ticket is used for.
2.2 A capability ticket which defines what information is the service provider capable of accessing.
2.3 A requested resource which represents sensitive information that the FPX network tries to protect. And a scope which represents the client's permission on the requested resources.
2.4 A linkage between requested resource and capability ticket.
Section 1: Client
A working Client (Service Provider) in FPX, requires data from the following data types, (listed in the order of creation):
- oauth-client-metadata
- oauth-client
- uma-client
Type: "oauth-client-metadata"
Defines additional data for the OAuth Client, e.g. authentication type, scope, secret, etc.
"" means empty string
For the oauth-client-metadata entity, do not set both jwksUri and jwksRaw together. If jwksUri is set, ensure that jwksRaw is null.
Attributes | Description | Example value | Required | Localizable |
---|---|---|---|---|
issuerUri | Provide host URL of Service Provider. This value can be used as a fallback to retrieve openid configuration details for the Service Provider by calling this URI at the .well-known/openid-configuration | https://some-service-provider.com | Yes | No |
clientType | Client type | Either CONFIDENTIAL or PUBLIC | Yes | No |
jwksRaw | Public key details registered directly into the database. A client can either register the public key set in this parameter or provide a URI in the jwksUri parameter to expose that endpoint and get the public key set. Must be set to null if jwksUri is populated. | For an example of this attribute, see the sample request to update oauth-client-metadata, below | Yes, if authentication type is private_key_jwt and jwksUri is empty | No |
jwksUri | URL of a set of keys containing the public keys. Can be left blank if jwksRaw is populated. Use of jwksUri is preferred over jwksRaw. | https://some-service-provider.com/jwks | Yes, if authentication type is private_key_jwt and jwksRaw is empty | No |
clientAuthenticationType | Authentication method | One of the following: - client_secret_basic - client_secret_post - client_secret_jwt - private_key_jwt | Yes | No |
grantTypes | Grant type | "refresh_token client_credentials authorization_code" | Yes | No |
scopes | Scopes of client. Likely not required as clients will use capability tickets | register | No | No |
clientSecret | Any string length <= 255 | client-secret | Yes, if authentication type is client_secret_post or client_secret_basic. This parameter should be null if the authentication type is set to private_key_jwt. | No |
Type: "oauth-client"
Defines Client ID and Redirect URI
Attribute | Description | Example value | Required | Localizable |
---|---|---|---|---|
clientId | Client identifier in string. | fpx-service-provider | Yes | No |
clientName | A human readable name for the client. | Identos Wallet | No | No |
redirectUris | URL for redirection after the request is authorized. | https://some-service-provider.com | No | No |
Relationship | Description | Required |
---|---|---|
oAuthClientMetaData | Linkage to metadata. The ID needs to be created before hand. | Yes |
Type: "uma-client"
Defines basic information for Service provider. For example, terms of service (tos), policy URL, OAuth client, etc.
Attribute | Description | Example value | Required | Localizable |
---|---|---|---|---|
iconUrl | Link to service provider icon | https://www.identos.ca/wp-content/themes/identos/images/logo.png | Yes | Yes |
baseUrl | Host of Service provider | https://identos.com/fpxsp | Yes | No |
name | Name of service provider | Service Provider Name | Yes | Yes |
policyUrl | Link to service provider policy | https://www.identos.ca/privacy-policy/ | Yes | Yes |
tosUrl | Link to service provider terms of service | https://www.identos.ca/legal/ | Yes | Yes |
umaClientId | Unique identifier of UMA Client ID | fpxsp | Yes | No |
disabledOn | Date and time at which the entity was, or will be, disabled. The value must be in "yyyy-MM-dd'T'HH:mm:ss'Z'" format. In order to re-enable, the value must be reset to the default value null . | "2021-01-01T11:00:00Z". | No | No |
Relationship | Description | Required |
---|---|---|
oauthClient | Linkage to oauth_client. The ID needs to be created beforehand. | Yes |
Sample Requests
Create a client (Service Provider) - All in one (OAuth Client Metadata, OAuth Client and UMA Client)
curl --location -g --request PATCH '{{AS_ADMIN_URI}}' \
--header 'Content-Type: application/vnd.api+json; ext=jsonpatch' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'ApiVersion: v1.0' \
--header 'Accept-Language: en' \
--data-raw '[
{
"op": "add",
"path": "/oauth-client-metadata",
"value": {
"id": 4,
"type": "oauth-client-metadata",
"attributes": {
"issuerUri": "https://some-service-provider.com/",
"clientAuthenticationType": "private_key_jwt",
"clientType": "CONFIDENTIAL",
"grantTypes": "client_credentials",
"jwksRaw": null,
"jwksUri": "https://some-service-provider.com/jwks",
"scopes": "uma_protection",
"clientSecret": null
}
}
},
{
"op": "add",
"path": "/oauth-client",
"value": {
"type": "oauth-client",
"id": 4,
"attributes": {
"clientId": "fpxsp",
"clientName": "FPX Service Provider",
"redirectUris": [
"https://some-service-provider.com",
"{{AS_URI}}"
]
},
"relationships": {
"oAuthClientMetaData": {
"data": {
"type": "oauth-client-metadata",
"id": 4
}
}
}
}
},
{
"op": "add",
"path": "/uma-client",
"value": {
"type": "uma-client",
"id": 1,
"attributes": {
"iconUrl": "",
"baseUrl": "https://identos.com/fpxsp",
"name": "Service Provider Name",
"policyUrl": "https://identos.com/fpxsp/policy/en",
"tosUrl": "https://identos.com/fpxsp/tosUrl/en",
"umaClientId": "fpxsp"
},
"relationships": {
"oauthClient": {
"data": {
"id": 4,
"type": "oauth-client"
}
}
}
}
}
]'
Get client related information - OAuthClient_Metadata
curl --location -g --request GET '{{AS_ADMIN_URI}}/oauth-client-metadata/4' \
--header 'Content-Type: application/vnd.api+json' \
--header 'ApiVersion: v1.0' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'Accept-Language: en'
Get client related information - OAuthClient
curl --location -g --request GET '{{AS_ADMIN_URI}}/oauth-client/4' \
--header 'Content-Type: application/vnd.api+json' \
--header 'ApiVersion: v1.0' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'Accept-Language: en'
Get client related information - UMAClient
curl --location -g --request GET '{{AS_ADMIN_URI}}/uma-client/1' \
--header 'Content-Type: application/vnd.api+json' \
--header 'ApiVersion: v1.0' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'Accept-Language: en'
Update Client - All in one (OAuth Client Metadata, OAuth Client and UMA Client)
curl --location -g --request PATCH '{{AS_ADMIN_URI}}' \
--header 'Content-Type: application/vnd.api+json; ext=jsonpatch' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'ApiVersion: v1.0' \
--header 'Accept-Language: en' \
--data-raw '[
{
"op": "replace",
"path": "/oauth-client-metadata/4",
"value": {
"id": 4,
"type": "oauth-client-metadata",
"attributes": {
"issuerUri": "https://some-service-provider.com/",
"clientAuthenticationType": "private_key_jwt",
"clientType": "CONFIDENTIAL",
"grantTypes": "client_credentials",
"jwksRaw": "{\"keys\":[{\"kty\":\"RSA\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"rsa1\",\"alg\":\"RS256\",\"n\":\"o-uKni7MWPz2tYxMIx3g6hhYWBCfdDizk7yhFZ14MX9MpHEjWvH983m1X8HcYaYhqRr3Lz-zGsanOy0DoSlmaXUjv90fy7MzoNs-c7cc3GRQrZAnL_UI2FSh9FhqqwZgyXMpleZY7-YDquEMQfZ9L2W5Q0pyYr5nNfSPX8FQWdV4kRwTjhPJT7RhntJ8A1X6KLj3aBseZge92jVtWAOD702GhxRjfyHcguVelf8-qFe8fJrODpQ2yCRbh1zrq5AY2MDiW1njy7t-GayqQG2alqPjZGH9f7uIHxtHNIKXF92OEVG4A_HPbDlJ2RxidCbYOnyESaho4ZayHOc6KlpXWQ\"}]}",
"jwksUri": null,
"scopes": "uma_protection",
"clientSecret": null
}
}
},
{
"op": "replace",
"path": "/oauth-client/4",
"value": {
"type": "oauth-client",
"id": 4,
"attributes": {
"clientId": "fpxsp",
"clientName": "FPX Service Provider",
"redirectUris": [
"https://some-service-provider.com",
"{{AS_URI}}"
]
},
"relationships": {
"oAuthClientMetaData": {
"data": {
"type": "oauth-client-metadata",
"id": 4
}
}
}
}
},
{
"op": "replace",
"path": "/uma-client/1",
"value": {
"type": "uma-client",
"id": 1,
"attributes": {
"iconUrl": "",
"baseUrl": "https://identos.com/fpxsp",
"name": "UMA-CLIENT-NAME-AZEZHDvMTQPKBgA2ZjazcVVtb9SEra-1653663342152",
"policyUrl": "UMA-CLIENT-POLICY_URI-09LnKmiSAlW2GEAFGRRhDLdYDBMWi5-1653663342153",
"tosUrl": "UMA-CLIENT-TOS_URI-M7dREBywjoKt52XdhZ2bd8CJluFQ53-1653663342155",
"umaClientId": "fpxsp"
},
"relationships": {
"oauthClient": {
"data": {
"id": 4,
"type": "oauth-client"
}
}
}
}
}
]'
Disable Client (UMA Client)
curl --location --request PATCH '{{AS_ADMIN_URI}}/uma-client/1' \
--header 'Content-Type: application/vnd.api+json' \
--header 'ApiVersion: v1.0' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--data-raw '{
"data": {
"type": "uma-client",
"id": "1",
"attributes": {
"disabledOn" : "2012-11-12T01:00:00Z"
}
}
}'
Section 2: Ticket
Tickets represent a bundle of resources that the client will request, leaving it up to the end user to choose sources. Ticket creation involves describing the purpose of the ticket, providing a UI-friendly name for the ticket, and defining which resources and associated scopes will be requested.
In order to log in, a Client may require many pieces of information from the end user, such as a name, email address, and address. Each of these attributes may come from a unique resource definition with a unique type, which many Resource Servers may be able to provide, or may be modeled as scopes within a single resource definition.
The available APIs and how they're set up as FPX resources and scopes is unique to your use-case
Type: "purpose"
Defines the purpose of capability ticket or requested resource scopes.
Attributes | Description | Example value | Required | Localizable |
---|---|---|---|---|
name | The name of the purpose | Any string e.g. "Service Provider A wants your email address" | Yes | Yes |
Sample Requests
Create a Purpose
curl --location -g --request PATCH '{{AS_ADMIN_URI}}' \
--header 'Content-Type: application/vnd.api+json; ext=jsonpatch' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'ApiVersion: v1.0' \
--header 'Accept-Language: en' \
--data-raw '[
{
"op": "add",
"path": "/purpose",
"value": {
"type": "purpose",
"id": 1,
"attributes": {
"name": "identity-profile access"
}
}
}
]'
Get a Purpose
curl --location -g --request GET '{{AS_ADMIN_URI}}/purpose/1' \
--header 'Content-Type: application/vnd.api+json' \
--header 'ApiVersion: v1.0' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'Accept-Language: en'
Update a Purpose
curl --location -g --request PATCH '{{AS_ADMIN_URI}}' \
--header 'Content-Type: application/vnd.api+json; ext=jsonpatch' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'ApiVersion: v1.0' \
--header 'Accept-Language: en' \
--data-raw '[
{
"op": "replace",
"path": "/purpose/1",
"value": {
"type": "purpose",
"id": 1,
"attributes": {
"name": "identity-profile access"
}
}
}
]'
Type: "capability-ticket"
A Capability Ticket allows a Client to request a set of pre-registered resources and scopes for a specific Purpose.
Attributes | Description | Example value | Required | Localizable |
---|---|---|---|---|
ticketId | A unique identifier for the Capability Ticket. | identity-profile | Yes | No |
ticketName | The readable name of the ticket. | Identity Ticket | Yes | Yes |
disabledOn | Date and time at which the entity was, or will be, disabled. The value must be in "yyyy-MM-dd'T'HH:mm:ss'Z'" format. In order to re-enable, the value must be reset to the default value null . | "2021-01-01T11:00:00Z" | No | No |
Relationship | Description | Required |
---|---|---|
purpose | The purpose of this ticket. E.g. it is used when a Client requests end-user email. | Yes |
umaClient | Client that is assigned to this ticket. | Yes |
Sample Requests
Create a Capability Ticket
curl --location -g --request PATCH '{{AS_ADMIN_URI}}' \
--header 'Content-Type: application/vnd.api+json; ext=jsonpatch' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'ApiVersion: v1.0' \
--header 'Accept-Language: en' \
--data-raw '[
{
"op": "add",
"path": "/capability-ticket",
"value": {
"type": "capability-ticket",
"id": 1,
"attributes": {
"ticketId": "identity-profile",
"ticketName": "Identity Ticket"
},
"relationships": {
"purpose": {
"data": {
"id": 1,
"type": "purpose"
}
},
"umaClient": {
"data": {
"id": 1,
"type": "uma-client"
}
}
}
}
}
]'
Get a Capability Ticket
curl --location -g --request GET '{{AS_ADMIN_URI}}/capability-ticket/1' \
--header 'Content-Type: application/vnd.api+json' \
--header 'ApiVersion: v1.0' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'Accept-Language: en'
Update a Capability Ticket
curl --location -g --request PATCH '{{AS_ADMIN_URI}}' \
--header 'Content-Type: application/vnd.api+json; ext=jsonpatch' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'ApiVersion: v1.0' \
--header 'Accept-Language: en' \
--data-raw '[
{
"op": "replace",
"path": "/capability-ticket/1",
"value": {
"type": "capability-ticket",
"id": 1,
"attributes": {
"ticketId": "identity-profile",
"ticketName": "Identity Ticket"
},
"relationships": {
"purpose": {
"data": {
"id": 1,
"type": "purpose"
}
},
"umaClient": {
"data": {
"id": 1,
"type": "uma-client"
}
}
}
}
}
]'
Disable a Capability Ticket
curl --location -g --request PATCH '{{AS_ADMIN_URI}}/capability-ticket/1' \
--header 'Content-Type: application/vnd.api+json' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'ApiVersion: v1.0' \
--header 'Accept-Language: en' \
--data-raw '{
"data": {
"type": "capability-ticket",
"id": 1,
"attributes": {
"disabledOn": "2021-01-01T11:00:00Z"
}
}
}'
The resources to be requested can each have different scopes. For example, most Clients may only require a 'read' scope to the email and proof of address resources, while others, such as government services may want 'read' access to email, but 'read' and 'write' access to proof of address so they can update information at the Resource Server directly when the user moves.
Type: "requested-resource"
Attributes | Description | Example value | Required | Localizable |
---|---|---|---|---|
maxPermissionDuration | Duration (in milliseconds) that a client is allowed to access the requested resource. | 300000000 | Yes | No |
requestedResourceId | Unique identifier that represents requested resource. | "requested-resource-2022-01-01-11112020" | Yes | No |
Relationship | Description | Required |
---|---|---|
resourceDefinition | Definition of a resource in FPX that needs to be created beforehand. | Yes |
umaClient | The onboarded Service Provider. | Yes |
Type: "requested-resource-scopes"
Relationship | Description | Required |
---|---|---|
scope | The generic scope entity in the database. It needs to be created beforehand. | Yes |
requestedResource | The resource that is requested by the Service Provider. | Yes |
Sample Requests
Create Requested Resource - All in one
curl --location -g --request PATCH '{{AS_ADMIN_URI}}' \
--header 'Content-Type: application/vnd.api+json; ext=jsonpatch' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'ApiVersion: v1.0' \
--header 'Accept-Language: en' \
--data-raw '[
{
"op": "add",
"path": "/requested-resource",
"value": {
"type": "requested-resource",
"id": 1,
"attributes": {
"maxPermissionDuration": 300000000,
"requestedResourceId": "8ddd9d0b-6776-4bfe-9865-b2fb9559b12312"
},
"relationships": {
"resourceDefinition": {
"data": {
"id": 1,
"type": "resource-definition"
}
},
"umaClient": {
"data": {
"id": 1,
"type": "uma-client"
}
}
}
}
},
{
"op": "add",
"path": "/requested-resource-scopes",
"value": {
"type": "requested-resource-scopes",
"id": 1,
"attributes": {},
"relationships": {
"scope": {
"data":
{
"id": 1,
"type": "scope"
}
},
"purpose": {
"data": {
"id": 1,
"type": "purpose"
}
},
"requestedResource": {
"data": {
"id": 1,
"type": "requested-resource"
}
}
}
}
},
{
"op": "add",
"path": "/requested-resource-scopes",
"value": {
"type": "requested-resource-scopes",
"id": 2,
"attributes": {},
"relationships": {
"scope": {
"data":
{
"id": 2,
"type": "scope"
}
},
"purpose": {
"data": {
"id": 1,
"type": "purpose"
}
},
"requestedResource": {
"data": {
"id": 1,
"type": "requested-resource"
}
}
}
}
}
]'
Get requested resource
curl --location -g --request GET '{{AS_ADMIN_URI}}/requested-resource/1' \
--header 'Content-Type: application/vnd.api+json' \
--header 'ApiVersion: v1.0' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'Accept-Language: en'
Get requested resource scope
curl --location -g --request GET '{{AS_ADMIN_URI}}/requested-resource-scopes/1' \
--header 'Content-Type: application/vnd.api+json' \
--header 'ApiVersion: v1.0' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'Accept-Language: en'
Update requested resource - All in one
requested_resource_id A.K.A rr_id is a foreign key in the request-resource-scope table.
If you want to update rr_id, you can use the following API to remove related entities first. Otherwise, the API will raise a foreign key update exception.
curl --location -g --request PATCH '{{AS_ADMIN_URI}}' \
--header 'Content-Type: application/vnd.api+json; ext=jsonpatch' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'ApiVersion: v1.0' \
--header 'Accept-Language: en' \
--data-raw '[
{
"op": "remove",
"path": "/requested-resource-scopes/1"
}
]'
curl --location -g --request PATCH '{{AS_ADMIN_URI}}' \
--header 'Content-Type: application/vnd.api+json; ext=jsonpatch' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'ApiVersion: v1.0' \
--header 'Accept-Language: en' \
--data-raw '[
{
"op": "replace",
"path": "/requested-resource/1",
"value": {
"type": "requested-resource",
"id": 1,
"attributes": {
"maxPermissionDuration": 300000000,
"requestedResourceId": "8ddd9d0b-6776-4bfe-9865-b2fb9559b12312"
},
"relationships": {
"resourceDefinition": {
"data": {
"id": 1,
"type": "resource-definition"
}
},
"umaClient": {
"data": {
"id": 1,
"type": "uma-client"
}
}
}
}
},
{
"op": "replace",
"path": "/requested-resource-scopes/1",
"value": {
"type": "requested-resource-scopes",
"id": 1,
"attributes": {},
"relationships": {
"scope": {
"data": {
"id": 1,
"type": "scope"
}
},
"purpose": {
"data": {
"id": 1,
"type": "purpose"
}
},
"requestedResource": {
"data": {
"id": 1,
"type": "requested-resource"
}
}
}
}
}
]'
Type: "requested-resources-capability-tickets"
Clients may have multiple tickets, and tickets can have multiple resources. The Admin User should only allow each Client to request the minimum scopes and resources that the Client can justify needing.
Requested Resource Capability
Relationship | Description | Required | Localizable |
---|---|---|---|
capabilityTicket | Capability ticket previously defined. | Yes | No |
requestedResource | Requested Resource previously defined. | Yes | No |
Sample Requests
Create Requested Resource Capability Ticket
curl --location -g --request PATCH '{{AS_ADMIN_URI}}' \
--header 'Content-Type: application/vnd.api+json; ext=jsonpatch' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'ApiVersion: v1.0' \
--header 'Accept-Language: en' \
--data-raw '[
{
"op": "add",
"path": "/requested-resources-capability-tickets",
"value": {
"type": "requested-resources-capability-tickets",
"id": 1,
"attributes": {},
"relationships": {
"capabilityTicket": {
"data": {
"type": "capability-ticket",
"id": 1
}
},
"requestedResource": {
"data": {
"type": "requested-resource",
"id": 1
}
}
}
}
}
]'
Get Requested Resource Capability Ticket
curl --location -g --request GET '{{AS_ADMIN_URI}}/requested-resources-capability-tickets/1' \
--header 'Content-Type: application/vnd.api+json' \
--header 'ApiVersion: v1.0' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'Accept-Language: en'
Update Requested Resource Capability Ticket
curl --location -g --request PATCH '{{AS_ADMIN_URI}}' \
--header 'Content-Type: application/vnd.api+json; ext=jsonpatch' \
--header 'Authorization: {{AS_ADMIN_STATIC_TOKEN}}' \
--header 'ApiVersion: v1.0' \
--header 'Accept-Language: en' \
--data-raw '[
{
"op": "replace",
"path": "/requested-resources-capability-tickets/1",
"value": {
"type": "requested-resources-capability-tickets",
"id": 1,
"attributes": {},
"relationships": {
"capabilityTicket": {
"data": {
"type": "capability-ticket",
"id": 1
}
},
"requestedResource": {
"data": {
"type": "requested-resource",
"id": 1
}
}
}
}
}
]'
The localization feature is covered in more detail here.