Full Integration Guide

Introduction

This document outlines the steps a retail partner of Afterpay needs to integrate with Afterpay’s OAuth user authentication capability.

OAuth integration gives consumers the ability to have the Afterpay and retailer account linked. After the accounts are linked with the oAuth token, consumers will not have to login to Afterpay from that retailer.

Goals

Reduce friction for consumers using Afterpay on retailer websites:

  • Provide consumers with the option to “link” their account with the retailer so that retailer can remember that Afterpay is their preferred payment method
  • Increase Afterpay checkout conversions by allowing consumers to skip the login
  • Use standard protocols to provide access to private consumer content, or act on behalf of consumers without the consumer sharing their credentials.

Approach

Use the OAuth 2.0 protocol to provide the necessary authorisation for a consumer to link their Afterpay account with the Merchant. OAuth will also provide the foundation for the Merchant to access private consumer content, or act on behalf of consumers.

  • Provide the Merchant with the ability to request access to a consumer’s account using an OAuth Authorization Request
  • Present the consumer with a screen showing the authorisation request from the Merchant. The consumer will be asked to accept or decline the request.
  • Provide the Merchant with the ability to create a Checkout on behalf of the consumer

OAuth Scopes

These are the OAuth scopes that will be required to perform the account link

ScopeDescription
profileAllows claims that represent basic profile information including: given_name, surname, update_at
emailReturns the email claim, which contains the Afterpay user's email address, and email_verified, which is a boolean indicating whether the email address was verified by the user.
create_checkoutAllows the grant holder to create a checkout on behalf of the consumer

Client Authentication

A set of client credentials used for authenticating will be issued. The Afterpay OAuth server requires the client to authenticate using HTTP basic authentication. The following credentials will be generated:

ParameterDescription
client_idRequired
The client identifier issued to merchant.
client_secretRequired
The client secret.

📘

Note:

client_id and client_secret are not the same as merchant_id and merchant_key

In basic authentication a request contains a header field in the form of Authorization: Basic , where credentials is the Base64 encoding of client_id and client_secret joined by a single colon :

Implementation

User Experience

Scenario 1: Opt in to link identity

Consumer is prompted to accept the Merchant authorization request to link their account:

Scenario 2: Consumer with linked identity skips login on any device

After a consumer has accepted the Merchant authorization request subsequent checkouts skip the login and go straight to the Afterpay summary page:

Technical

Flow 1: Identity Not Linked

In this scenario a consumer who has not linked their identity with the Merchant is presented with a screen to link their account.

This screen is shown after the consumer logs in. In the OAuth flow this is called the “authorization request” screen. The consumer can accept or decline the request. The authorization code is returned at the end of the checkout along with the checkout status.

We have chosen to combine the OAuth authorization request with the Afterpay checkout flow to avoid the consumer being redirected more than necessary.

A typical OAuth flow would direct the user to the OAuth authorization request where they accept/decline the request before being redirected back to the client. If we follow this approach the consumer could be redirected twice. Once for the OAuth authorization and once at the end of the checkout. Multiple redirects could have a negative impact on conversion.

Flow diagram

Checkout Request

For example, the Merchant will launch the Afterpay window using the current checkout URL. The following parameters are used to begin the combined checkout flow and the authorization request flow:

  • response_type
    The response_type should be set to code, indicating that you expect to receive an authorization code if successful
  • client_id
    The client_id is your public identifier
  • scope
    The scope values you are requesting, comma separated. See OAuth Scopes section .
  • state
    The state parameter that you provide will be returned unmodified in the redirect url.
  • redirect_uri
    The URI that will be redirected to after checkout. This must match one of the values given to Afterpay when setting up your OAuth credentials.

Afterpay control when to show the account link request screen. The presence of the above authorization request parameters does not mandate an authorization request.

Example request
Location: https://portal.afterpay.com/au/checkout/?token=001.xxx&state=xxxx
&response_type=code&client_id=123456&scope=create_checkout%20email%20profile&redirect_uri=https://merchantwebsite.com/

Checkout Response

After the consumer completes the checkout they are redirected to the merchant `redirectConfirmUrl` with the additional authorization code.
Example response
Location: https://merchant.com/checkout?status=SUCCESS&orderToken=xxxx
&code=xxx&state=xxx&redirect_uri=https://merchantwebsite.com/

When the account link screen is not displayed to the consumer, no authorization response parameters are returned, except for the state parameter that was included in the request URL

Checkout Error Response

If the consumer denied the authorisation request, but confirmed their order, the checkout would redirect to the merchant redirectConfirmUrl with a checkout status of SUCCESS. The “error” parameter is added to the redirect URL to inform Merchant of the error.

Example error
Location: https://merchant.com/checkout?status=SUCCESS&orderToken=xxxx
&error=xxx&state=xxx

If the authorization request fails due to errors such as access_denied, unauthorized_client, invalid_scope, etc. the consumer will complete the checkout process and be redirected with the “error” parameter in the URL. Please note that the “error” parameter and the “status” parameter are independent variables. The presence of an error parameter doesn’t imply a cancelled checkout.

As per the Error Response specification, if the client id is missing or invalid no error is returned. The consumer will complete the checkout flow as and be redirected with a checkout status of SUCCESS or CANCELLED.

Authorization Code Request

When an authorization code is returned, the Merchant can exchange the code for an access token and a refresh token using the Afterpay OAuth API. The following example shows an authorization code grant request. Please note, as this is an application/x-www-form-url encoded request, the parameters for grant_type and refresh_token should be encoded into the request body, not as URL parameters:

Example Request
POST /oauth/token
Host: auth.afterpay.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-type: application/x-www-form-urlencoded

grant_type=authorization_code&code=xxxxx&redirect_uri=https://merchantwebsite.com

A successful response will look like the following:

Example response
HTTP 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "access_token": "xxxx",
  "token_type": "bearer",
  "expires_in": 3600,
  "refresh_token": "xxxx"
} 

To prevent a replay attack, the authorization code can only be used once. Subsequent requests using the same code will be rejected.

The authorization code has a lifetime of 10 minutes, after which time it will expire and no longer be valid.

An error response will look like the following:

Example response
HTTP 400 Bad Request
Content-Type: application/json
Cache-Control: no-store

{
  "error": "invalid_request"
} 

User Info Request

To retrieve the user info for a linked account, make a GET request to the user info endpoint and pass the access token.

Example request
GET /oauth/v1/userinfo
Host: auth.afterpay.com
Authorization: Bearer xxxxx
Example response
HTTP 200 OK
Content-Type: application/json
Cache-Control: no-store

{
   "name": "Alice Doe",
   "given_name": "Alice",
   "family_name": "Doe",
   "email": "[email protected]",
   “uuid”: “57a06500-014b-11eb-adc1-0242ac120002”
   "email_verfiied": true
}

Flow 2: Identity Linked

After a consumer has linked their identity and chooses Afterpay, the Merchant calls the Create Checkout endpoint using the consumer’s access token. The checkout window is opened and the consumer skips the Afterpay login and is taken to the payment summary screen.

Skip login is made possible because the checkout token is associated with their account.

Flow Diagram

Create Checkout Request

For a consumer with a linked account, create the checkout by sending the access token. If the access token is valid and authorised, the Checkout is created on behalf of the consumer who authorised the access token.

The Checkout will be attributed to a Merchant that has been associated by default with the client to whom the access token belongs (this is configured by Afterpay when setting up OAuth client credentials). If you wish to attribute the checkout to another Afterpay merchant, the credentials of that merchant will need to be provided in an additional header (see example below).

If the access token has expired, you will need to refresh it using your Refresh token. See the section Refreshing Access Tokens for more details.

The following example shows a create checkout request with the access token in the payload. This checkout will be attributed to the Merchant associated with the client to whom the access token belongs.

Example Request
POST /v2/checkouts
Host: api.afterpay.com
Content-Type: application/json
Authorization: Bearer xxxxx

{
  ...
}

📘

Note:

If you are a payment platform that manages the checkout experience on behalf of merchants, you’d need to use the Create Checkout request below to ensure that the checkout gets correctly attributed to the end merchant.

The following example shows a create checkout request with the access token in the payload, along with an additional header (x-apt-on-behalf-of) containing the base64 encoded merchant credentials of a merchant to whom the checkout should be attributed. In this scenario, the client does not need to be configured with default association to an Afterpay Merchant.

Example request
POST /v2/checkouts
Host: api.afterpay.com
Content-Type: application/json
Authorization: Bearer xxxxx
x-apt-on-behalf-of: Basic dGVzdG1lcmNoYW50a2V5OnRlc3RtZXJjaGFudHNlY3JldA==

{
  ...
}
Encoding Credentials
echo -n "clientID:clientSecret" | base64

📘

Note:

The clientSecret here should be your plaintext password, not the BCrypt encoded password provided to Afterpay when onboarding.

Flow 3: Refreshing Access Tokens

Access tokens expire after 5 minutes. If your access token has expired you can use the refresh token to obtain a new access token. If the consumer has explicitly revoked Merchant access, the request for a new access token will be denied.

Your refresh token is long lived (valid for 10 years), however some reasons it may longer be valid include:

  • Afterpay auth server has revoked the refresh token
  • The consumer has revoked their consent for the authorization

Flow Diagram

Example request
POST /oauth/token
Host: auth.afterpay.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=xxxxx
Example response

The response to the refresh token grant is the same as when issuing an access token except that it doesn’t include the refresh token. The current refresh token will continue to be valid.

A successful response will look like the following:

HTTP 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "access_token": "xxxx",
  "token_type": "bearer",
  "expires_in": 3600
}

An error response will look like the following:

HTTP 400 Bad Request
Content-Type: application/json
Cache-Control: no-store

{
  "error": "invalid_request"
} 

If the refresh token is invalid or revoked the authorisation server will return the following response:

HTTP 400 Bad Request
Content-Type: application/json

{
  "error": "invalid_grant"
} 

Flow 4: Revoking Access

There are multiple ways access can be revoke:

  • The consumer wishes to revoke Merchant access from the Afterpay Consumer Portal
  • The consumer wishes to delink their Afterpay identity from the Merchant
  • Afterpay has determined the client has been compromised.

Flow diagram showing revoke request

Merchant Delink Request

When a merchant wishes to delink a customer account, a POST request is sent to /oauth/revoke with Client Authentication and the refresh token to revoke.

Example request
POST /oauth/revoke
Host: auth.afterpay.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-type: application/x-www-form-urlencoded

token=xxxxx

Afterpay Delink Request

Consumers have the possibility to delink the merchant account in the Afterpay Consumer Portal in their profile settings.

Security

Account Takeover

In an account takeover attack, the attacker intercepts the checkout token and uses it to open the checkout window. Once in the checkout the attacker can confirm the order and view information such as their last 4 digits of their card number. Confirming the order will have no material gain to the attacker.

Countermeasures to be introduced in the future

This kind of attack can be mitigated by:

  • Replace the current cookie authentication strategy with an JWT access token that is scoped to the specific checkout token that it was created for and for the purpose of performing a checkout payment flow only.
  • Only allowing the checkout token to be used once for the generation of a JWT access token.

Testing Environments

OAuth Endpoints

EnvironmentRegionsURL
SandboxU.S / CAauth-sandbox.us.afterpay.com
SandboxAU / NZauth-sandbox.afterpay.com
SandboxGB / EUauth.eu-sandbox.clearpay.co.uk
ProductionU.S / CAauth.us.afterpay.com
ProductionAU / NZauth.afterpay.com
ProductionGB / EUauth.eu.afterpay.clearpay.co.uk

Checkout Endpoints

EnvironmentRegionsURL
SandboxU.S / CAapi.us-sandbox.afterpay.com
SandboxAU / NZapi-sandbox.afterpay.com
SandboxGB / EUapi.eu-sandbox.afterpay.com
ProductionU.S / CAapi.us.afterpay.com
ProductionAU / NZapi.afterpay.com
ProductionGB / EUapi.eu.afterpay.com

❗️

Important

OAuth does not currently support the Global API.