Skip to content

Delegated Authentication

Treezor allows you to use its OAuth industry standard authentication mechanism to authenticate your customers trourough your application.

Delegating the authentication to Treezor allows you to focus on your business while having the peace of mind provided by an expertly set up authentication mechanism.

Using Treezor as an Identity Provider means that:

  • You don't have to handle passwords yourself (nor password retrievals/resets)
  • You don't need to maintain a database of User credentials
  • You don't need to keep up with hashing and salting best practices
  • You only keep an association between the userId provided by Treezor authentication mechanism and the User's information in your own databases
Paperclip icon

Prerequisites – To use delegated authentication, you need

  • To onboard end users with Connect – Creates their credentials in Treezor Identity Provider.
  • A post-authentication URL to be declared to Connect – Where users are redirected after authenticating with Treezor.
  • A private/public key pair to be generated by Treezor – The public key will be provided to you, allowing you to assert the Tokens authenticity.

Flow

Logging-in

When a User shows up to your application and doesn't have a JWT, you redirect them to a customizable login page hosted by Treezor.

The User enters their credentials and submits the login form.

If the authentication is successful, the user is redirected to a previously configured URL of your application with a code query parameter appended by Treezor.

In and of itself, the code doesn't allow you to authenticate the User. You will have to exchange this single-use code for a JWT using the following request.

bash
curl -X POST {baseUrl}/oauth/token \
	--form 'grant_type="authorization_code"' \		# mandatory
	--form 'code="{yourTemporaryCode}"' \			# mandatory
	--form 'client_id="{yourClientId}"' \			# mandatory
#	--form 'scope="<SCOPE>"'						# optional, if you want a specific scope

Returns an object containing the User's JWT.

json
{
    "token_type": "Bearer",
    "expires_in": 3600,
    "access_token": "{theUsersAccessToken}",
	"refresh_token": "{theTokenAllowingForJwtRefresh}"
}

The User can now add this access_token in the Authentication header of all requests made to your application so that you can authenticate them.

Authenticating

To authenticate an End User, you must:

Asserting the JWT legitimacy

Lock icon

Security – Ensure your application validates the JWT legitimacy

Your must implement and test this step with great care. Were your application to accidentally accept invalid tokens would leave it open to anyone.

To check that the token is legitimate, you will use:

  • The User's JWT Token,
  • The RSASSA_PKCS1_V1_5_SHA_256 algorithm,
  • Your Connect public key.

The User's JWT is composed of three sections each encoded in base64 and separated by dots.

  • The second section is the token payload
  • The last section is the token signature

Consider the following JWT, as provided by your User in the Authentication header.

json
eyJ0eXAiOiJKV1QiLCJhbGciOiJSU0FTU0FfUEtDUzFfVjFfNV9TSEFfMjU2In0.eyJpc3MiOiJ0cmVlem9yX2Nvbm5lY3QiLCJpYXQiOjE2MzM1MTMyMjEsImV4cCI6MTYzMzUxNjgyMSwic3ViIjoiNzkwMzdlNmUtYzFlMS00MmYyLWJlOWEtZTI0OWM3NjdjNDc2Iiwic2NvcGUiOlsiYWRtaW4iLCJrZXlzIiwibGVnYWwiLCJyZWFkX29ubHkiLCJyZWFkX3dyaXRlIiwicmVhZF9hbGwiXSwidXNlcklkIjpudWxsLCJjYXJkcyI6W10sIndhbGxldHMiOltdLCJjaGlsZHJlbiI6W10sInVzZXJUeXBlIjoiYXBwbGljYXRpb24iLCJjbGllbnRJZCI6IjkyOTI1MiJ9.cPWi6RY1n0tPIJ1jG8600wZQvMUU1eIZPq1uzIju7OI8SnJ77FBmj25q8w0JcUwGIZf0GDKI51tovi0aqFNZsVrsP1V8o3b_5eJiEA2LtUVimAyWWtheMEa1J5Seqh3_rH5BO0xos2fRXM6CyFK1xDwc5EJeD0Pko5Yq3ls4-bcJt3yYBPH3JkaaADt2ettYATnpv9KnBeTPU7INDwNd2d6orVdc0yUgx9dmO9-NPbYBQuNsPTDOV8nnCWu6P0RAqUdjDZKbrr71Vj61ULur5yIr0oHLYg--80p6mgrMMAbPHQTKHO-wrcA94NvTCQ_5STXxUVfxh34xbOotdmeUeQ

You encrypt the payload using the RSASSA_PKCS1_V1_5_SHA_256 algorithm and Connect public key.

bash
# an example will soon be provided
aws kms sign \
	--key-id '{connectPublicKey}' \
	--signing-algorithm RSASSA_PKCS1_V1_5_SHA_256 \
	--message '{payload}'

You then compare the newly generated signature with the JWT signature.

  • If they match: you can proceed to the next step.
  • If they do not match:
    • Deny any access to your application,
    • Consider the event as a potential attack and take appropriate measures.

Extracting the User's identity

As you now can trust the token Payload, simply use a base64 decoding function on the token second section (payload).

bash
base64 -d "eyJpc3MiOiJ0cmVlem9yX2Nvbm5lY3QiLCJpYXQiOjE2MzM1MTMyMjEsImV4cCI6MTYzMzUxNjgyMSwic3ViIjoiNzkwMzdlNmUtYzFlMS00MmYyLWJlOWEtZTI0OWM3NjdjNDc2Iiwic2NvcGUiOlsiYWRtaW4iLCJrZXlzIiwibGVnYWwiLCJyZWFkX29ubHkiLCJyZWFkX3dyaXRlIiwicmVhZF9hbGwiXSwidXNlcklkIjpudWxsLCJjYXJkcyI6W10sIndhbGxldHMiOltdLCJjaGlsZHJlbiI6W10sInVzZXJUeXBlIjoiYXBwbGljYXRpb24iLCJjbGllbnRJZCI6IjkyOTI1MiJ9"

Returns the decoded payload.

json
{
	"iss": "treezor_connect",
	"iat": 1624439479,
	"exp": 1624443079,
	"sub": "79037e6e-c1e1-42f2-be9a-e249c767c476", // here is the trzConnectUserId
	"scope": [
		"keys",
		"legal",
		"read_only",
		"read_write",
		"read_all"
	],
	"userId": {userId},	// here is the userId
	"clientId": {yourClientId}, 
	"cards": [],
	"wallets": [],
	"children": [],
	"userType": "user"
}

Note that two distinct IDs are contained in this object:

  • userId used across the Treezor API to identify the User (to use to match Connect Users with your locally stored Users).
  • sub (trzConnectUserId) used initially during the Connect Onboarding, and when changing password.

It is very important to store the userId as a string since userId will be migrated to UUID in the future.

Now you could for example retrieve your locally stored User using the following pseudocode:

java
try {

	// assert that the JWT signature is valid 
	// and retrieve trzConnectUserId from the JWT payload
	connectUserId = JWT
		.assertSignatureIntegrity()
		.decodePayload()
		.getConnectUserId()

}
catch(Exception authenticationError) {

	// The JWT has an invalid signature, forbid access and terminate
	App.die(authenticationError.toString(), 403)

}

// retrieve the locally stored User from your database
customer = Customers.getByConnectUserId(connectUserId)

// perform any action necessary : display wallets balances, recent operations, etc.
wallets = customer.getWallets()
books icon

Reading – Learn more about OAuth

You may find OAuth website helpful in implementing Treezor's OAuth Identity Provider.