
User Management with GraphQL
On this page
This tutorial shows how to manage user account data within your applications by connecting to GraphQL endpoints. First ensure that you are running version 7.0 or later of the Curity Identity Server. The tutorial will explain the setup for an example scenario where a customer portal application is used by administrators to manage user accounts.
Identity Server Setup
When managing user accounts, the Curity Identity Server acts as a Web API, so you must present an access token and use scopes and claims for authorization. In order to provide a secure and flexible solution, there are a few layers, which are explained in the following sections.
Prerequisites
This guide assumes that you have run the Basic Setup Wizard and configured a data source, as well as an Authentication Profile, Token Service Profile and User Management Profile.
GraphQL in the Curity Identity Server is supported for JDBC data sources, and for other data sources you can instead use SCIM Endpoints. This tutorial will assume that user accounts are stored in a PostgreSQL database:

Add the GraphQL User Management Endpoint
To start using GraphQL for user accounts, first add an endpoint of type um-graphql-api
to the User Management Service.

Configure Scopes and Claims
This tutorial's client application will use a scope called accounts
that contains a groups
claim. You must either use the built-in claim name urn:se:curity:claims:admin:groups
or the specific claim name groups
, and in this tutorial the latter option is used. It is important to ensure that the scope is then included in access tokens under the Claims Mapper
section:

The groups claim must evaluate to an array of strings. This tutorial will use the following hard coded value, though various types of ClaimsValueProvider
can be used if required, to assign values according to custom logic. See the Adding Claims tutorial for an example.

Create an Authorization Manager
Next navigate to System → Authorization and add an Authorization Manager with the Groups
type.

Then map the manager to the accounts
scope. The below scope enables full control over all user accounts, though in a real application it is recommended to only assign the permissions needed. The admin
value from the groups claim will then map to these authorization rules at runtime:

Next, use the manager in the User Management Profile. Go to Profiles -> User Management -> General. In the Authorization section choose the previously created Authorization Manager.

Get an Access Token
For the purposes of this tutorial use a simple Client Credentials based client to get an access token. A real customer portal would instead use the Code Flow, where the process would be equivalent, to just add the accounts
scope to that app's configuration. The test client can be imported from the following XML, and for convenience it also has the introspection capability, to enable verifying that the access token is issued with the expected groups
claim:
<config xmlns="http://tail-f.com/ns/config/1.0"><profiles xmlns="https://curity.se/ns/conf/base"><profile><id>oauth-dev</id><type xmlns:as="https://curity.se/ns/conf/profile/oauth">as:oauth-service</type><settings><authorization-server xmlns="https://curity.se/ns/conf/profile/oauth"><client-store><config-backed><client><id>accounts-client</id><client-name>accounts-client</client-name><secret>Password1</secret><scope>accounts</scope><capabilities><client-credentials/><introspection/></capabilities><use-pairwise-subject-identifiers><sector-identifier>accounts-client</sector-identifier></use-pairwise-subject-identifiers></client></config-backed></client-store></authorization-server></settings></profile></profiles></config>
An access token can then be retrieved and introspected using the following curl requests, or alternatively you could perform the same operations using OAuth Tools. These examples use an HTTP setup, to avoid SSL trust issues on a development computer, though of course any deployed system would instead use HTTPS. (To switch to HTTP go to System -> Deployment and change the Protocol used by the Default
service role.)
OPAQUE_ACCESS_TOKEN=$(curl -s -k -X POST http://localhost:8443/oauth/v2/oauth-token \-H 'content-type: application/x-www-form-urlencoded' \-d 'grant_type=client_credentials&client_id=accounts-client&client_secret=Password1&scope=accounts' \| jq -r '.access_token')echo $OPAQUE_ACCESS_TOKENcurl -s -k -X POST http://localhost:8443/oauth/v2/oauth-introspect \-u "accounts-client:Password1" \-H "Accept: application/json" \-H "Content-Type: application/x-www-form-urlencoded" \-d "token=$OPAQUE_ACCESS_TOKEN" | jq
The inspection result can be verified to ensure that the groups
array claim has the expected value:

Connect With a Client
Now that an access token is available, tools can be used to connect to the GraphQL endpoint of the Curity Identity Server. First download and install the Insomnia tool. In the app, create a new GraphQL request and enter the URL of the API endpoint, which in this tutorial is http://localhost:8443/um/graphql/admin
.
An access token must be provided to make requests to the GraphQL API and so that the Insomnia tool can download the API schema. Do this by selecting Bearer
from the Auth dropdown and entering the opaque access token retrieved earlier:

Once you enter a valid token, Insomnia retrieves the schema silently in the background. You can view it via the schema / show documentation menu command.

Working with Account Data
Use example queries
The queries and mutations from this section can be pasted into the GraphQL pane of Insomnia and sent as POST requests.
You can retrieve the fields available on the main Account
object with this GraphQL introspection command, though you may prefer to just use the intellisense to see which fields are available. The response will include a name and description for each field.
query getAccountSchema{__type(name:"Account") {fields {namedescription}}}
Find a particular user account using one of the lookup methods:
Only active users by default
The default behavior when creating accounts using the GraphQL API is to set active=false
(or 0). The default behavior unless explicitly defined is also to only list accounts where active=true
(or 1).
The result is that an account could be created in one query and if the accounts are listed in a subsequent query, it will not be available.
Either explicitly set active=true
when creating the account or include active=false
accounts in the query listing users.
query findAccount{accountByEmail(email: "jane.doe@mycompany.com") {idname {givenNamemiddleNamefamilyNameformatted}preferredLanguagedisplayNamelinkedAccounts {value}}}
The results are then returned in the standard GraphQL JSON response format, containing the fields requested within a data
section:
{"data": {"accountByEmail": {"id": "4d807914-ab51-11ec-b593-0242ac170002","name": {"givenName": "Jane","middleName": null,"familyName": "Doe","formatted": "Jane Doe"},"preferredLanguage": null,"displayName": null,"linkedAccounts": []}}}
Some companies will have a large volume of user accounts, so pagination is used when working with lists, to ensure that queries are efficient. Select a list of the first 10 user accounts like this:
query getAccounts{accounts(first: 10) {edges {node {idname {givenNamemiddleNamefamilyName}userNameemails {valueprimary}}}}}
During querying, intellisense features are available to explain the meaning of each object and field:

To make data changing commands you can use GraphQL mutations. When creating a user account you can optionally also set a password:
mutation createAccount{createAccount(input: {fields: {userName: "john.doe",password: "Password1",emails: {value: "john.doe@mycompany.com",primary: true}}}) {account {userNameemails {value}}}}
The following example shows an update operation for a user account whose name has changed, so that the userName
, displayName
and email
fields are all set to new values:
mutation updateAccount{updateAccountById(input: {accountId: "fbea947a-aabc-11ec-adcb-0242ac170002",fields: {userName: "jane.smith"displayName: "jane.smith"emails: {value: "jane.smith@mycompany.com"primary: true}}}) {account {displayNameemails {value}}}}
Finally, user accounts can be deleted with the following syntax:
mutation deleteAccount{deleteAccountById(input: {accountId: "fbea947a-aabc-11ec-adcb-0242ac170002"}) {deleted}}
There are potentially many other GraphQL features you can use, to put you in better control of your identity data, though the above examples will enable you to get connected.
Custom User Fields
Starting in version 7.2 of the Curity Identity Server, GraphQL can be used to save custom fields against user accounts. First you need to define custom fields in the Admin UI under User Management Service / General
. The following example extends the GraphQL schema to add a string field and a numeric field:

You can then run a mutation of the following form to populate the custom fields for a user and save them to the user account data. This example query also echoes back the values in the mutation response.
mutation updateAccount{updateAccountById(input: {accountId: "4d807914-ab51-11ec-b593-0242ac170002",fields: {Custom1: "A string value"Custom2: 123}}) {account {Custom1Custom2}}}
The custom values are then saved within the attributes
column of the data row for the user account, and can then be retrieved in the same way as any other GraphQL field. The values can then be used during authentication and token issuing. The Working with Claims tutorial describes how to include custom values from user account data in access tokens.
Users and Dynamic Clients
In some security use cases, Dynamic Client Registration (DCR) is used to register one or more distinct OAuth clients per user. This technique is described in Mobile Best Practices, where a separate dynamic client is registered per user and device. The Authenticated DCR mobile code example provides a working end-to-end solution.
From version 7.2 of the Curity Identity Server, dynamic clients mapped to users can also be accessed using GraphQL. First enable access to the additional data under User Management Service / General
:

You can then use GraphQL to read details from the dynamically_registered_clients
database table. The result set could potentially contain multiple dynamic clients per user, and the DCR fields are described in the Using Dynamic Client Registration article.
query findAccount{accountByEmail(email: "demo@user.com") {idname {givenNamefamilyName}emails {value}dynamicClients {client_idscope}}}
All of this data can then be accessed for any user with an account record. As for other areas of the schema, GraphQL tooling will enable you to easily see which DCR fields are available:

Programmatic Clients
Once the above data access techniques are understood, you can begin GraphQL coding against user accounts in your own apps. There are many client libraries available to choose from, in all the main technology stacks. These provide similar features to the Insomnia tool, to enable productive development.
Conclusion
User accounts in the Curity Identity Server are easy to manage in your own apps. GraphQL endpoints provide a friendly API with modern tooling for developers, though SCIM endpoints are also available, and may be a better choice for some types of operation. To use GraphQL you must connect securely, with an access token that has the expected groups scope, and which maps to an Authorization Manager, where the level of access is defined.