# Non-hosted standalone For full control over your authentication flow, use non-hosted sessions. The authentication process is managed by your back end. --- ## Eligibility To use Google Secure Payment Authentication (SPA), your authentication request must include the following fields: - `challenge_indicator` set to one of the following: - `no_preference` – Default value - `no_challenge_requested` - `challenge_requested` - `challenge_requested_mandate` - `authentication_type` set to `regular` – Default value - `channel_data.channel` set to `browser` Additionally, Google SPA requires Android devices using Chrome browsers. > **Note** > > Google SPA does not support network token payments. If Google deems your authentication request ineligible for SPA, Checkout.com automatically fall backs your request to 3DS if it's included in your preferred experiences. Otherwise, the authentication will fail. --- ## Allow Google Payment Request API Google SPA relies on Google's Payment Request API to complete the payment. If you host the payment page within an iframe, you must configure it to allow cross-origin resources to use the Payment Request API. Ensure you add this permission to the iframe that loads the authentication and all its parent iframes: ```html ``` --- ## Payment authorization After a successful Google SPA authentication, you receive a provisioned Device Primary Account Number (DPAN) token, along with the ECI and cryptogram. You must submit your subsequent payment request as a token payment using the DPAN token retrieved from authentication along with the ECI and cryptogram with your chosen PSP. --- ## Authenticate your requests ### Access tokens All Sessions API endpoints will accept a valid JSON web token (JWT) bearer token. These short-lived tokens can be generated using your client ID and secret, which you received after creating your account. Tokens must contain the scope `sessions:browser` for browser channel flows. Google SPA only supports the browser channel, meaning other channel types (like apps) are not supported. ### Session secret When you create a session, you get a `session_secret` property. You must use this session secret in the `Authorization` header of subsequent requests for that session. The `session_secret` is a short-lived randomly generated string that can only be used for actions taken on a specific session, minimizing the risk of exposure. Unlike client secrets used for JWT token generation, the session_secret is not shared with the frontend, reducing the vulnerability to malicious third-party access. --- ## Step 1: Request a session Include `google_spa` in the request's `preferred_experiences` field. Ensure you include multiple options in your authentication request. This approach provides you additional insight to help you determine your strategy and retry the authentication using an alternative experience if needed. The experience that you list first takes precedence and becomes the preferred option. If the authentication request is deemed ineligible by Google prior to the authentication being processed, Checkout.com automatically falls back to 3DS. When you create a session with channel data, you do not need to update the channel data later on. ### Request example ```json { "source": { "type": "card", "number": "4485040371536584", "expiry_month": 1, "expiry_year": 2030 }, "amount": 100, "currency": "USD", "authentication_type": "regular", "authentication_category": "payment", "challenge_indicator": "no_preference", "reference": "ORD-5023-4E89", "transaction_type": "goods_service", "shipping_address": { "address_line1": "123 Anywhere St.", "address_line2": "Apt. 456", "city": "Anytown", "zip": "AB12 3CD", "country": "GB" }, "completion": { "type": "non_hosted", "callback_url": "http://example.com/sessions/callback" }, "preferred_experiences": [ "google_spa", "3ds" ] } ``` ### Response example If you receive a `202 - Accepted` response, your request was successful. The response contains: - The session ID (prefixed by `sid_`) - A `next_actions` property, which indicates the next steps required to finalize the session. ```json { "id": "sid_uyf763hgstqena6ei5omawyxs4", "transaction_id": "e9df0645-38dc-4823-8f9e-4378d0625b13", "amount": 100, "currency": "GBP", "completed": false, "authentication_type": "regular", "authentication_category": "payment", "status": "pending", "next_actions": [ "collect_channel_data" ], "transaction_type": "goods_service", "scheme": "visa", "authentication_date": "2024-09-17T15:19:44.2393677Z", "challenge_indicator": "no_preference", "preferred_experiences": { "preferred_experiences": { "3ds": { "status": "available" }, "google_spa": { "status": "available" } }, "_links": { "self": { "href": "https://sessions.cko-qa.ckotech.co/sessions/sid_uyf763hgstqena6ei5omawyxs4" }, "collect_channel_data": { "href": "https://sessions.cko-qa.ckotech.co/sessions/sid_iudn72o4harurd46in4nays3cm/collect-data" }, "callback_url": { "href": "https://google.com/" } } } } ``` --- ## Step 2: Get sessions details To make an authentication request you must gather the details of the browser that initiated the session. To get this data, call the [Get session details](https://api-reference.checkout.com/tag/Standalone/#operation/getSession) endpoint setting the `{id}` query parameter using the `id` value you received in the sessions response, prefixed with `sid_`. > **Information** > > You can skip this step if your back end forwards the response of requesting a new session to your front end. ### Response example If the request is successful, you receive a `200 - OK` response, along with a response containing the details of the authentication, along with the `next_actions` property, which indicates you what to do next: ```json { "id": "sid_y2tlt2pd6ptu7fwlsz5ovmndea", "transaction_id": "e9b9a6c6-f3e3-4fe7-96cb-967aeab1a320", "amount": 100, "currency": "GBP", "completed": false, "authentication_type": "regular", "authentication_category": "payment", "status": "pending", "next_actions": ["collect_channel_data"], "challenge_indicator": "no_preference", "preferred_experiences": { "3ds": { "status": "available" }, "google_spa": { "status": "available" } }, "_links": { "self": { "href": "https://sessions.cko-qa.ckotech.co/sessions/sid_y2tlt2pd6ptu7fwlsz5ovmndea" }, "collect_channel_data": { "href": "https://sessions.cko-qa.ckotech.co/sessions/sid_y2tlt2pd6ptu7fwlsz5ovmndea/collect-data" }, "callback_url": { "href": "https://google.com/" } } } ``` For the full API specification, see the [API reference](https://api-reference.checkout.com/). | Field name | Description | | --- | --- | | `id`
`string` | The unique identifier of the session. | | `next_actions`
`array` | Specifies what action to take to complete the session. Will be one of: `collect_channel_data`, `challenge_cardholder`, or `complete`. | | `status`
`string` | The status of the session. | | `preferred_experiences`
`object` | Provides information about the list of preferred experiences passed in the sessions request and their status | | `preferred_experiences.3ds`
`object` | Contains all information about 3DS experience at that stage of authentication | | `preferred_experiences.3ds.status`
`string` | The status of 3DS experience | | `preferred_experiences.3ds.status_reason`
`string` | The status reason in case of failure if authentication was processed using 3DS experience | | `preferred_experiences.google_spa`
`object` | Contains all information about google_spa experience | | `preferred_experiences.google_spa.status`
`string` | The status of google_spa experience | | `preferred_experiences.google_spa.status_reason`
`string` | The status reason in case of failure if authentication was processed using google_spa experience | --- ## Step 3: Collect channel data If the `next_actions` field returns `collect_channel_data`, you must update the session with the device channel data. To update the session, call the [Update a session](https://api-reference.checkout.com/tag/Standalone/#operation/updateSession) endpoint: **Live** `PUT` `https://{prefix}.api.checkout.com/sessions/{session_id}/collect-data` **Sandbox** `PUT` `https://{prefix}.api.sandbox.checkout.com/sessions/{session_id}/collect-data` ### Request example ```json { "channel": "browser", "accept_header": "Accept: ., q=0.1", "java_enabled": true, "javascript_enabled": true, "language": "FR-fr", "color_depth": "16", "screen_height": "1080", "screen_width": "1920", "timezone": "60", "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", "three_ds_method_completion": "U", "ip_address": "1.12.123.255", "iframe_payment_allowed": true, "user_agent_client_hint": "'Sec-CH-UA: ' Not A;Brand';v='99', 'Chromium';v='96', 'Google Chrome';v='96''\n'" } ``` | Field name | Description | | --- | --- | | `channel`
`string` | Required.

Indicates the interface (browser) being used to initiate the transaction. Set this to the browser. | | `accept_header`
`string` | Required.

Exact content of the HTTP accept headers from the cardholder's browser. | | `java_enabled`
`boolean` | Required.

Boolean that represents the ability of the cardholder browser to execute Java. The value is returned from the navigator.javaEnabled property. | | `javascript_enabled`
`boolean` | Boolean that represents the ability of the cardholder browser to execute JavaScript. Default: true | | `language`
`string` | Required.

Value representing the browser language as defined in IETF BCP47. Returned from the navigator.language property. | | `color_depth`
`string` | Required.

Value representing the bit depth of the color palette for displaying images, in bits per pixel. Obtained from the cardholder's browser using the `screen.colorDepth` property. | | `screen_height`
`string` | Required.

Total height of the cardholder's screen in pixels. Value is returned from the `screen.height` property. | | `screen_width`
`string` | Required.

Total width of the cardholder's screen in pixels. Value is returned from the `screen.width` property. | | `timezone`
`string` | Required.

Time difference between UTC time and the local time of the cardholder's browser, in minutes. | | `user_agent`
`string` | Required.

Exact content of the HTTP `user-agent` header. | | `ip_address`
`string` | Required.

IP address of the browser as returned by the HTTP headers. | | `user_agent_client_hint`
`string` | The raw `Sec-CH-UA` header value. This can improve Google SPA support. For example – `"Chromium";v="96" ` | #### Response example After providing channel data, an authentication request is sent to Google, resulting in one of the following authentication responses: - `unavailable` - `declined` - `rejected` - `challenged` This outcome is reflected in the `next_actions` property of the update response. #### Key response fields | Field name | Description | | --- | --- | | `id`
`string` | The unique identifier of the session. | | `next_actions`
`array` | Specifies what action to take to complete the session. Will be one of: `challenge_cardholder`, or `complete`. | | `status`
`string` | The status of the session. | | `preferred_experiences`
`object` | Provides information about the list of preferred experiences passed in the sessions request and their status. | | `preferred_experiences.3ds`
`object` | The field contains all information about 3DS experience. | | `preferred_experiences.3ds.status`
`string` | The status of 3DS experience. | | `preferred_experiences.3ds.status_reason`
`string` | The status reason in case of failure if authentication was processed using 3DS experience. | | `preferred_experiences.google_spa`
`object` | The field contains all information about `google_spa` experience. | | `preferred_experiences.google_spa.status`
`string` | The status of `google_spa` experience. | | `preferred_experiences.google_spa.status_reason`
`string` | The status reason in case of failure if authentication was processed using `google_spa` experience. | | `google_spa`
`object` | Provides more details related to `google_spa` experience. | | `google_spa.challenge_url`
`string` | Fully qualified URL of the Google SPA frontend for user challenge. | | `google_spa.initial_timeout`
`string` | Indicates amount of time (in minutes) allowed for establishing initial connection to user's specific authentication session (as determined by `challengeURL` and `params`) | | `google_spa.max_timeout`
`string` | Indicates maximum amount of time (in minutes) allowed for completing all PSP-Google message exchanges for the current authentication session. | | `google_spa.iframe`
`object` | Contains the information about the iframe to render challenge. | | `google_spa.iframe.height`
`string` | A string value which gives the percentage height of the iframe. The possible values are 0 and 100%. | | `google_spa.iframe.width`
`string` | A string value which gives the percentage width of the iframe. The possible values are 0 and 100%. | The possible statuses of the experiences are: - `unavailable` – Google SPA is unavailable due to ineligibility or technical issue, if you provided 3DS as a preferred experience, we will automatically fallback to 3DS. - `available` – The experience is available. - `processed` – The authentication was processed with this experience. - `unprocessed` – The authentication was not processed with this experience. ```json { "id": "sid_uyf763hgstqena6ei5omawyxs4", "transaction_id": "6cff0ba6-94e6-46e0-83c4-475cc05b1797", "amount": 100, "currency": "GBP", "completed": false, "authentication_type": "regular", "authentication_category": "payment", "status": "challenged", "next_actions": [ "challenge_cardholder" ], "transaction_type": "goods_service", "scheme": "visa", "authentication_date": "2024-09-18T10:54:57.7287097Z", "flow_type": "challenged", "challenge_indicator": "no_preference", "preferred_experiences": { "3ds": { "status": "unprocessed" }, "google_spa": { "status": "processed" } }, "experience": "google_spa", "google_spa": { "challenge_url": "https://sessions-ext.cko-qa.ckotech.co/simulator/google-authentication/auth?sid=8af7a367-d087-4f94-8002-ce7b73133543&cid=6cff0ba6-94e6-46e0-83c4-475cc05b1797&origin=", "initial_timeout": "00:15:00", "max_timeout": "00:01:00", "iframe": { "height": "100%", "width": "100%" } }, "_links": { "self": { "href": "https://sessions.cko-qa.ckotech.co/sessions/sid_uyf763hgstqena6ei5omawyxs4" }, "callback_url": { "href": "https://google.com/" } } } ``` --- ## Step 4: Challenge All authentications processed with Google SPA are challenged. If `next_action` is `challenge_cardholder`, you must handle the challenge flow for Google SPA. This step is not applicable if the `google_spa` experience status field returns `unavailable`. You can either fully redirect, or host the challenge page in an iframe. Google recommends that you render the challenge inside an iframe so you have full control over the final size on your page. > **Information** > > If you host the challenge page within an iframe, ensure you configure it to allow cross-origin resources as instructed in [Allow Google Payment Request API](#Allow_Google_Payment_Request_API) #### Render the challenge You must redirect the cardholder to the `google_spa.challenge_url` URL returned in the response. ##### Iframe Size If you use an iframe, refer to the `google_spa.iframe` object to determine the size and render the iframe that embeds Google's `challenge_url`. These values are decided by Google and you must comply with them when you display the challenge to the cardholder. Possible iframe sizes are: - `0 x 0` - `100% x 100%` #### Notification of outcome To be informed of the outcome of the authentication, use the message event on the front end to listen to a `window.postMessage` method from the iframes. For example, if the Google landing page executes the following script: ```javascript window.parent.postMessage( 'SPA_AUTHENTICATION_SUCCEEDED' , MERCHANT_WEBSITE_ORIGIN); ``` The embedding page must add the following listener: ```javascript window.addEventListener( "message" , (e)=> { if (msg.origin ==='MERCHANT_WEBSITE_ORIGIN' ) { if (msg.data === 'SPA_AUTHENTICATION_SUCCEEDED' ) { // close the iframe, do other specific action } if (msg.data === 'SPA_AUTHENTICATION_FAILED' ) { // close the iframe, do other specific action } if (msg.data === 'SPA_AUTHENTICATION_CANCELLED' ) { // close the iframe, do other specific action } } }); ``` After receiving the notification, call the [Get session details](https://api-reference.checkout.com/tag/Standalone/#operation/getSession) endpoint setting the `{id}` query parameter using the `id` value you received in the sessions response to retrieve the updated details of the authentication. The ID is prefixed with `sid_`. #### Full Redirect mode If you are using the full page redirect, you must ensure that you include the `google_spa` object in your request. This object must contain the `continue_url`, which serves as the redirect URL the cardholder is redirected to after completing the authentication step. Do not use `continue_url` if you're using an iframe as it will not be loadable and you will risk a broken flow. #### Request example ```json { "source": { "type": "card", "number": "4895379980026585", "expiry_month": 7, "expiry_year": 2024, "scheme": "visa", "name": "Hannah Bret", "email": "cardholder@checkout.com" }, "processing_channel_id": "pc_h43ig6azpm7uxlqndurrz7pfbu", "preferred_experiences": ["google_spa", "3ds"], "amount": "100", "currency": "GBP", "completion": { "type": "non_hosted" }, "google_spa":{ "continue_url": "https://google.com" } } ``` #### Challenge completed After completing the challenge flow, the session moves to a final state where you to choose to complete the session. To access the `eci`, `cryptogram`, and `google_spa.token` fields required for authorization after a successful Google SPA authentication, retrieve the session details using a JWT token instead of the session secret. Using a JWT token safeguards these sensitive values from potential client-side exposure. The authentication must be completed within 15 minutes of the request being submitted, otherwise the authentication expires. --- ## Step 5: Get sessions details (Post Challenge) After the Google SPA authentication is completed, you must call the [Get session details](https://api-reference.checkout.com/tag/Standalone/#operation/getSession) endpoint to retrieve the required information. ### Response example ```json { "id": "sid_uyf763hgstqena6ei5omawyxs4", "transaction_id": "3c741b93-d949-4851-8751-21bc299690f2", "amount": 10, "currency": "GBP", "authentication_type": "regular", "authentication_category": "payment", "status": "approved", "status_reason": "rreq_status", "approved": true, "next_actions": [], "challenged": true, "cryptogram": "ADYBAJBXIwAANiQGEVcjmAdXIwA=", "transaction_type": "goods_service", "eci": "05", "scheme": "visa", "authentication_date": "2024-10-07T11:02:14.2766861Z", "flow_type": "challenged", "challenge_indicator": "no_preference", "preferred_experiences": { "3ds": { "status": "unprocessed" }, "google_spa": { "status": "processed" } }, "experience": "google_spa", "google_spa": { "token": { "number": "4485040371536584", "expiry_month": 1, "expiry_year": 30 } }, "_links": { "self": { "href": "https://sessions.cko-qa.ckotech.co/sessions/sid_uyf763hgstqena6ei5omawyxs4" } } } ``` For the full API specification, see the [API reference](https://api-reference.checkout.com/). ### Key fields | Field name | Description | | --- | --- | | `id`
`string` | The unique identifier of the session. | | `next_actions`
`array` | Specifies what action to take to complete the session. Should be `complete`. | | `status`
`string` | The status of the session. Should be one of the following: `expired`, `approved`, `unavailable`, `declined`, `rejected`. | | `preferred_experiences`
`object` | Provides information about the list of preferred experiences passed in the sessions request and their status. | | `preferred_experiences.3ds`
`object` | Contains all information about 3DS experience at that stage of authentication. | | `preferred_experiences.3ds.status`
`string` | The status of 3DS experience. | | `preferred_experiences.3ds.status_reason`
`string` | The status reason in case of failure if authentication was processed using 3DS experience. | | `preferred_experiences.google_spa`
`object` | Contains all information about `google_spa` experience. | | `preferred_experiences.google_spa.status`
`string` | The status of `google_spa` experience. | | `preferred_experiences.google_spa.status_reason`
`string` | The status reason in case of failure if authentication was processed using `google_spa` experience. | | `experience`
`string` | The experience used to process the authentication. For example, `google_spa`. | | `google_spa`
`object` | Provides details related to the google SPA experience. | | `google_spa.token`
`object` | Details of the Device Primary Account Number (DPAN) token. | | `google_spa.token.number`
`string` | The Device Primary Account Number (DPAN) token. | | `google_spa.token.expiry_month`
`integer` | The expiry month of the Device Primary Account Number (DPAN) token. | | `google_spa.token.expiry_year`
`integer` | The expiry year of the Device Primary Account Number (DPAN) token. | | `google_spa.initial_timeout`
`string` | Indicates amount of time (in minutes) allowed for establishing initial connection to user's specific authentication session (as determined by `challengeURL` and `params`). | | `google_spa.max_timeout`
`string` | Indicates maximum amount of time (in minutes) allowed for completing all PSP-Google message exchanges for the current authentication session. | If the authentication status is `approved`, you can authorize the payment. If the authentication is unavailable due to technical issues, you can decide whether or not to proceed with the payment, based on your risk assessment. If the `google_spa` authentication was unsuccessful after being challenged, you can retry using 3DS by re-sending the request with the `preferred_experience` array set to `3ds`. #### Google Token (DPAN) After a successful Google SPA authentication, Checkout.com returns a `google_spa.token` object which contains the DPAN card number and its expiry month and year. You must use this token (DPAN) to process the payment authorization as you would with a network token payment. #### Fallback and Retries If Google SPA is unavailable due to ineligibility or a technical issue, Checkout.com automatically falls back to 3DS, if it's included in your preferred experiences. This fallback is only possible if the session status is not `challenged`. If Google SPA fails after the status is challenged, you can retry using 3DS. To do so, submit a new request and set the `preferred_experience` array to `3ds`. ### Session properties #### Session status The following table shows the possible values of the `status` field: | Field name | Description | | --- | --- | | `pending` | Authentication has been requested and the session has been started. | | `approved` | The payment has been successfully authenticated. | | `unavailable` | Authentication experience unavailable because of ineligibility or technical issues. | | `declined` | The authentication was not authenticated. The issuer declined the authentication. | | `rejected` | The authentication was rejected. The issuer is rejecting the authentication and it should not be retried nor should authorization not be attempted. | | `challenged` | The issuer requires that the cardholder be presented with a challenge. | | `expired` | The authentication was not completed within 15 minutes. | #### Next actions The following table shows the possible values for the `next_actions` field. These values indicate the next steps required to finalize the session. | Field name | Description | | --- | --- | | `action` | The action to be taken. | | `description` | The description of the action. |