Ping SDKs

Token Vault

Token Vault provides an additional layer of security for storing and using OAuth 2.0 and OpenID Connect 1.0 tokens in your JavaScript single-page applications (SPAs).

Intended audience

Token Vault is complex to set up.

It is designed for situations that demand the highest level of client-side security for OAuth 2.0 token management.

Token Vault might be suitable in these scenarios:

  • Your industry has compliance or regulatory requirements, such as those for financial or government organizations

  • You need to run untrusted, third-party code in your main application, such as from external advertisers, or other embedded applications

Due to the complexity of deployment, we recommend considering alternative solutions if your use case does not absolutely require the high level of client-side security that the Token Vault offers.

Alternative solutions include:

  • Reduced Access Token lifetimes, without using refresh tokens

  • Reduced idle timeouts on sessions with user-event-driven "keep-alive" requests

  • Reduction or elimination of third-party code

  • Usage of a server-side Backend For Frontend (BFF) approach for storing tokens

Implemented as a plugin for the Ping SDK for JavaScript, Token Vault provides a feature called origin isolation.

Web applications can only access data that gets stored within the matching origin - the unique combination of protocol (usually HTTPS), hostname, and port number.

By storing OAuth 2.0 and OpenID Connect 1.0 tokens under a different origin than your main application, you are isolating these tokens from malicious code.

Your main app uses the Ping SDK for JavaScript as usual to request tokens and access protected resources, however the Token Vault intercepts these requests and manages related tokens in the isolated origin.

As your main app does not get access to the contents of the isolated tokens, they are protected from being exposed or reused in attacks such as cross-site scripting.

Token Vault components

Token Vault consists of two main components:

Token Vault Proxy

The Token Vault Proxy is responsible for:

  • Receiving and storing tokens in responses from your authorization server

  • Redacting responses from your authorization server that contain token values, before passing the redacted response to your application

  • Attaching stored tokens to requests that match the configured list of endpoints that require authorization

The Token Vault Proxy is embedded into your main application by using an inline frame, or iframe. An embedded iframe has a parent-child relationship with the main app, and the two can communicate with one another as long as they share the same parent domain, such as example.com.

To enable isolation, however, the origins must be different. For example, if your main app is served from https://sdkapp.example.com, the Token Vault Proxy could be served from https://proxy.example.com.

Token Vault Interceptor

The Token Vault Interceptor is implemented as a service worker on your main app and intercepts requests to URLs that match a configured list.

These URLs are your protected resources and therefore require authorization to access. The Token Vault Interceptor captures these requests and passes them to the Token Vault Proxy iframe to add the relevant tokens.

The Token Vault Interceptor is also responsible for capturing OAuth 2.0 calls from the SDK to the authorization server and routing them through the Token Vault Proxy. The Token Vault Proxy forwards these requests to the authorization server and stores the returned tokens inside its own origin away from your main app.

Token Vault flow

The following diagram gives a simplified high-level overview of how the Token Vault isolates tokens away from your main application:

token-vault
  1. When your app uses the Ping SDK to request tokens from your authorization server it uses the Authorization Code Flow with PKCE. The last step in this flow is a call to the /access_token endpoint.

  2. The Token Vault Interceptor captures this call to the /access_token endpoint.

  3. The Token Vault Interceptor forwards the call to the Token Vault Proxy to handle instead of going directly to your authorization server.

    The Token Vault Proxy completes the authorization code flow and captures the tokens from the response. It stores the tokens securely in its origin, which is different from your main app but shares the parent domain. The Token Vault Proxy can attach these stored tokens to any future calls routed through it that require authorization.

  4. The Token Vault Proxy then returns a redacted version of the response body. This ensures the main app never receives or stores the tokens.

    Example of a redacted response body
    {
      "accessToken": "REDACTED",
      "idToken": "eyJ0eXAiOiJKV1QiLCJra...7r8soMCk8A7QdQpg",
      "refreshToken": "REDACTED",
      "tokenExpiry": 1690712227226,
    }
  5. The SDK makes the redacted response available to your application.

  6. Your app can now make requests for protected resources that require authorization.

  7. If the protected resource matches a value on the configured list then the Token Vault Interceptor routes the request through the Token Vault Proxy.

  8. The Token Vault Proxy attaches the tokens it has stored in its own origin to the request and sends the request to the resource server.

  9. If the request has valid authorization bearer tokens attached, the resource server returns the protected content.

  10. The protected resource is returned to the main app.

    If the tokens were invalid or expired in the previous step, the main app receives a 400 error instead. In this case your app must restart the authorization code flow.