Our identity service supports the following use cases:

  1. Allowing a user to connect to a financial institution and grant permissioned access to their data from that financial institution.
  2. Allowing a user to connect to multiple financial institutions through a single profile and gain access to the data from those institutions.

We provide these features via an OpenID Provider interface that supports standard OAuth 2 based flows to issue access tokens that can be used to gain access to financial data via our API Gateway.

Moneyhub Data API Swagger documentation

Flow for First use case - Single connection and one time access

Connecting to a financial institution

  • Partner generates an authorisation url to the Authorisation Endpoint with the Financial Institution scope to connect to and the Data scopes required as part of the Claims
  • Partner redirects user to the authorisation url
  • Moneyhub Auth API gains consent from the user to access their banking data
  • Moneyhub Auth API redirects the user to the bank
  • Bank authenticates the user and sends them back to the Moneyhub Auth API
  • Moneyhub redirects the user back to the partner with an authorization_code
  • Partner exchanges this code for an access_token using the Token endpoint
  • Partner uses the access token at the Moneyhub Data API to access user’s financial data

Interactive guide for one time access

Flow for Second use case - Multiple connections and ongoing access

Registering a user and connecting to a financial institution

  • Partner requests an access token from the identity service with the scope user:create using the Token endpoint
  • Partner uses this token to create a profile at the User endpoint
  • Partner generates an authorisation url to the Authorisation Endpoint with the Financial Institution scope to connect to, and with the id of the new user profile as part of the Claims
  • Partner redirects user to the authorisation url
  • Moneyhub Auth API gains consent from the user to access their banking data
  • Moneyhub Auth API redirects the user to the bank
  • Bank authenticates the user and sends them back to the Moneyhub Auth API
  • Moneyhub redirects the user back to the partner with an authorization_code
  • Partner exchanges the authorization_code for an access_token and id_tokento complete the connection using the Token endpoint. This access_token do not contains any data scopes so it can’t be used to gain access to the user’s financial data. The id_token contains the connection_id
  • Partner requests an access token from the Moneyhub Auth API with the Data scopes required and a sub parameter in the Claims that contains the profile id using the Token endpoint
  • Partner uses the access token at the Moneyhub Data API to access the user’s financial data

Interactive guide for ongoing access

This example assumes the use of an OpenID Client (e.g. Node OpenId client)

const { access_token } = await client.grant({
  grant_type: "client_credentials",
  scope: "user:create",
})

const user = await got.post(`#{identityServiceUrl}/`, {
  headers: {
    Authorization: `Bearer ${access_token}`,
  },
  json: true,
  body: { clientUserId: "some-id" },
})

const authParams = {
  client_id: client_id,
  scope: "openid id:some-bankid",
  state: "your-state-value",
  redirect_uri: redirect_uri,
  response_type: "code",
  prompt: "consent",
}

const claims = {
  id_token: {
    sub: {
      essential: true,
      value: user.userId,
    },
    mh:con_id: {
      essential: true,
    },
  },
}

const request = await client.requestObject({
  ...authParams,
  claims,
  max_age: 86400,
})

const url = client.authorizationUrl({
  ...authParams,
  request,
})

// redirect the user to this url
// if everything is succesful they will be redirected to your `redirect_uri` with `code` and `state` as query parameters.

const tokens = await client.authorizationCallback(
  redirect_uri,
  { code, state },
  { state: expectedState }
)
// these tokens confirm that the account has been added, however cannot be used for data access
// the `id_token` will contain the id of the connection that has just been created

const { access_token } = await client.grant({
  grant_type: "client_credentials",
  scope: "accounts:read transactions:read:all",
  sub: user.userId,
})

const accounts = await got(`#{resourceServerUrl}/accounts`, {
  headers: {
    Authorization: `Bearer ${access_token}`,
  },
  json: true,
})

const transactions = await got(`#{resourceServerUrl}/transactions`, {
  headers: {
    Authorization: `Bearer ${access_token}`,
  },
  json: true,
})
```