---
# System prepended metadata

title: PPCP Mobile - Access Token Research

---

# PPCP Mobile - Access Token Research

5/23/23

## Problem Statement

The PPCP mobile SDKs require merchants to pass an [access token](https://developer.paypal.com/reference/get-an-access-token/) from their server to initialize the iOS and Android SDK.

[We just learned](https://paypal.slack.com/archives/C03QXJAFCJE/p1682705915425729) from solutions engineers that this token type is unsafe to store on the client, as it's scope is too high.

### Current Auth

Currently, the access token is being generated like [this](https://developer.paypal.com/reference/get-an-access-token/) on a merchant's server, and then sent to the client:

```
curl -v https://api-m.sandbox.paypal.com/v1/oauth2/token
 -H "Accept: application/json"
 -H "Accept-Language: en_US"
 -u "<Base64(client_id:secret)>"
 -d "grant_type=client_credentials"
```

This allows all API calls in our SDK to succeed. The problem is that it requires a `secret`.

### Option 1: Upgraded AccessToken

The merchant provides the SDK with a client ID and the SDK generates an access token to use with each API call:

```
curl -v POST 'https://api.sandbox.paypal.com/v1/oauth2/token' \
 -H 'Authorization: Basic <Base64(client_id:)>' \
 -H 'Content-Type: application/x-www-form-urlencoded' \
 -d '"grant_type=client_credentials&response_type=token&return_authn_schemes=true"'
```

[See ppass docs](https://ppaas/api/3719176155269356#apiReference).

The resulting `access_token` is then used as `Authorization: Bearer <access_token>` throughout the SDK.

#### Problem API `v2/checkout/orders` :no_entry: 

Using an upgraded access token works for all API requests in our SDK *except* `GET` from `v2/checkout/orders`.

*Request*:
```
curl -v GET https://api.sandbox.paypal.com/v2/checkout/orders/54379698LR790821X
 -H 'Authorization: Bearer A21AAIcMa9bpO_bwlov1XCbipeNBL1OxRBO1AhBxpBozfmcQ1mI4DZNU0V8VIz7mxBEOFipeNwEyDOhGy1tZwA2EjJnjDlJ3Q'
 -H 'Content-Type: application/json'
 -H 'Accept-Language: en_US'
```

*Response*:

```
Status 403

{
  "name": "NOT_AUTHORIZED",
  "details": [
    {
      "issue": "PERMISSION_DENIED",
      "description": "You do not have permission to access or perform operations on this resource."
    }
  ],
  "message": "Authorization failed due to insufficient permissions.",
  "debug_id": "7ab55d0aa422f",
  "links": [
    {
      "href": "https://developer.paypal.com/docs/api/orders/v2/#error-PERMISSION_DENIED",
      "rel": "information_link"
    }
  ]
}
```

ClientID used: `AcXwOk3dof7NCNcriyS8RVh5q39ozvdWUF9oHPrWqfyrDS4AwVdKe32Axuk2ADo6rI_31Vv6MGgOyzRt`

### Option 2: ClientID only

The merchant provides the SDK with a client ID, which is directly used by the SDK for authorization to subsequent API calls. 

The `client_id` would be used as `Authorization: Basic <Base64(client_id:)>` throughout the SDK.

This results in the same 403 as Option 1 above when  performing `GET` to `v2/checkout/orders` :no_entry:.

### Option 3: Avoid the call to `GET` `v2/checkout/orders`

This call is currently used to look up an order IDs `status` after a 3DS card challenge completes ([see example snippet](https://github.com/paypal/iOS-SDK/blob/c2a9029cf1bf3fb62623c8eab239e8ad72d8edaf/Sources/CardPayments/CardClient.swift#L101)).

If the challenge succeeds and we get a valid redirectURL back from the browser, can we just assume success? The merchant can technically get the `status` of their order on the server-side. We can make an assumption in the SDK, that if the redirectURL does not contain an error string, that the merchant is OK to continue on with their auth/capture.