Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions playbooks/wxcc-token-service-firebase/APPHUB.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# APPHUB.yaml — Playbook metadata for Webex App Hub
# Copy this file into your Playbook folder under playbooks/<tool-slug>/
# Fill in all required fields. See CONTRIBUTING.md for field rules.

# -----------------------------------------------------------------------------
# friendly_id — Unique identifier. Must end with -playbook (e.g. epic-ehr-playbook)
# -----------------------------------------------------------------------------
friendly_id: "wxcc-token-service-firebase-playbook"

# -----------------------------------------------------------------------------
# title — Display name for the Playbook (matches ContentStack field)
# -----------------------------------------------------------------------------
title: "Webex Contact Center — Cloud Function token service (Firestore)"

# -----------------------------------------------------------------------------
# tag_line — Short tagline for App Hub detail page (required, max 128 chars)
# -----------------------------------------------------------------------------
tag_line: "Serverless WxCC tokens: GCF + Firestore, GET ?name=, passphrase header, OAuth callback and refresh."

# -----------------------------------------------------------------------------
# description — App Hub supports Markdown. Use a block scalar (description: |) with
# blank lines between sections: opening paragraph (bold key terms), **Why use this
# playbook** (3–5 outcome bullets), **What it does** (concrete behaviors/endpoints).
# Do not put upstream repo URLs or install-only instructions here—use README and
# src/README.md for reference playbooks. See docs/commands/import_playbook.md.
# -----------------------------------------------------------------------------
description: |
A **Node.js** **Google Cloud Function** with **Firebase Firestore** that stores
**Webex OAuth** client settings and tokens, completes the **authorization code**
callback, and serves **GET** requests that return a fresh **Webex Contact Center**
**access token** for cloud callers (flows, automation, HTTP clients).

**Why use this playbook**

- **Cloud-native URL:** One **HTTPS** endpoint on **Google Cloud** instead of
operating your own VM for token storage when your stack is already GCP/Firebase.
- **Flow-friendly pattern:** Callers send **`?name=`** and a shared **`x-token-passphrase`**
header—easy to wire from **Flow Designer** or similar HTTP steps once network
access is allowed.
- **Documented Webex APIs:** Uses **`https://webexapis.com/v1/access_token`** for
code exchange and **refresh_token** grants—no undocumented endpoints.
- **Clear limits:** Describes **Firestore** layout, **`/init`** setup-only risk,
and when to repeat browser **OAuth** after **refresh** expiry.

**What it does**

- **`/callback`** — Exchanges **`code`** for tokens and merges them into the
**`tokens/{state}`** document in **Firestore**.
- **`/init`** — Creates an empty token document (setup only; dangerous if misused
in production).
- **GET** with **`name`** query — Validates **`TOKEN_PASSPHRASE`**, returns
**access token** if valid long enough, otherwise refreshes when **refresh token**
is still valid.

# -----------------------------------------------------------------------------
# product_types — Where this Playbook appears. Pick one or more.
# Valid: teams | meetings | calling | rooms | contact_center
# -----------------------------------------------------------------------------
product_types:
- "contact_center"

# -----------------------------------------------------------------------------
# app_context — Where the integration runs. Pick one or more.
# Valid: space | in_meeting | call | device | contact_center | sidebar | mcp | a2a
# -----------------------------------------------------------------------------
app_context:
- "contact_center"

# -----------------------------------------------------------------------------
# categories — App Hub category slugs. Pick one or more.
# Verticals: healthcare | financial-services | retail-ecommerce
# App categories (use kebab-case slugs):
# ai-agent-testing-observability | agent-supervisor-tools | analytics |
# calendar-scheduling | collaboration-management | customer-relations |
# customer-support | developer-tools | doc-management | education |
# finance | government | healthcare | human-resources | internet-of-things |
# marketing-sales | orchestration | platform | productivity |
# project-management | recording-transcriptions | security-compliance |
# self-service-bots | social-and-fun | strategy-team-planning |
# workflow-automation | workforce-optimization | other
# -----------------------------------------------------------------------------
categories:
- "developer-tools"
- "security-compliance"
- "workflow-automation"

# -----------------------------------------------------------------------------
# company_name — Your company or team name
# -----------------------------------------------------------------------------
company_name: "Webex for Developers"

# -----------------------------------------------------------------------------
# company_url — Your company or project URL
# -----------------------------------------------------------------------------
company_url: "https://developer.webex.com"

# -----------------------------------------------------------------------------
# support_url — Issues or support link (e.g. GitHub issues)
# -----------------------------------------------------------------------------
support_url: "https://github.com/webex/webexplaybooks/issues"

# -----------------------------------------------------------------------------
# product_url — Link to this Playbook in the repo (required)
# -----------------------------------------------------------------------------
product_url: "https://github.com/webex/webexplaybooks/tree/main/playbooks/wxcc-token-service-firebase"

# -----------------------------------------------------------------------------
# logo — (Optional) URL to your logo image. If not provided, defaults to the
# standard Webex Playbook logo.
# -----------------------------------------------------------------------------
logo: "https://images.contentstack.io/v3/assets/bltd14fd2a03236233f/blta2de9daa773c6604/60f71f81e2de935fc7e35dbe/download"

# -----------------------------------------------------------------------------
# estimated_implementation_time — e.g. "2-4 hours", "1 day"
# -----------------------------------------------------------------------------
estimated_implementation_time: "2-4 hours"

# -----------------------------------------------------------------------------
# third_party_tool — (Optional) The tool being integrated (e.g. Salesforce, Epic)
# Omit for generic playbooks (e.g. "any CMS")
# -----------------------------------------------------------------------------

# -----------------------------------------------------------------------------
# privacy_url — Privacy policy URL (required; use Cisco default for Webex-authored)
# -----------------------------------------------------------------------------
privacy_url: "https://www.cisco.com/c/en/us/about/legal/privacy-full.html"

# -----------------------------------------------------------------------------
# submission_date — (Optional) ISO date (e.g. 2025-03-01)
# -----------------------------------------------------------------------------
submission_date: "2026-04-02"
71 changes: 71 additions & 0 deletions playbooks/wxcc-token-service-firebase/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Webex Contact Center token service (Firebase) Playbook

This Playbook is adapted from the [token-service-sample](https://github.com/WebexSamples/webex-contact-center-api-samples/tree/main/token-management-samples/token-service-sample) in the Webex Contact Center API samples repository on GitHub.

## Use Case Overview

**Webex Contact Center** flows and cloud integrations (for example Flow Designer HTTP activities, JDS, or Webex Connect) often need a **callable HTTPS endpoint** that returns a **current Webex access token** without storing client secrets inside the flow. This sample deploys a **Google Cloud Function** backed by **Firestore** so token storage and refresh run next to Google Cloud/Firebase infrastructure.

**Target persona:** Developers or integration engineers who already use **Google Cloud** and **Firebase**, can register a **Webex Integration**, and are comfortable deploying functions and editing Firestore documents.

**Estimated implementation time:** 2–4 hours (GCP/Firebase project, deploy function with `TOKEN_PASSPHRASE`, deploy Firestore rules, register Integration redirect URI, run `/init`, paste OAuth client fields into Firestore, complete browser OAuth, verify GET with `?name=` and header).

**Compared to [wxcc-token-management-sample](../wxcc-token-management-sample/README.md):** that Playbook uses **Express + SQLite** on infrastructure you operate. This Playbook uses **managed Cloud Functions + Firestore** when you want a **serverless** URL for cloud-to-cloud calls.

## Architecture

An **HTTP-triggered Cloud Function** (`exports.tokenService` in [`src/index.js`](src/index.js)) handles three paths:

1. **`/callback`** — OAuth redirect from Webex; exchanges `code` for tokens using `clientId`, `clientSecret`, and `redirectUri` read from the Firestore document named by the OAuth `state` parameter (your token name).
2. **`/init`** — **Setup only:** creates or merges a `tokens/{name}` document with empty OAuth client fields. Do not call in production after configuration is complete (see [docs/upstream-overview.md](docs/upstream-overview.md)).
3. **GET** (root path with query `name`) — Validates header **`x-token-passphrase`** against environment variable **`TOKEN_PASSPHRASE`**, loads the token document, returns the access token if it has more than **two hours** left, otherwise refreshes via **`https://webexapis.com/v1/access_token`** if the refresh token is still valid (at least **two minutes** remaining per upstream logic).

**Firestore** holds per-token OAuth client credentials and tokens. **firestore.rules** denies direct client SDK access so data is intended to be maintained via the Admin SDK inside the function or the Firebase console.

See the [architecture diagram](diagrams/architecture-diagram.md) for the sequence view.

## Prerequisites

- **Google Cloud** project and billing appropriate for **Cloud Functions** and **Firestore** ([creating projects](https://cloud.google.com/resource-manager/docs/creating-managing-projects)).
- **Firebase** linked to the project ([Firebase Console](https://console.firebase.google.com)), Firestore in **Native** mode.
- **Node.js** 18 aligned with [`src/package.json`](src/package.json) for local packaging or CI checks (deployment is still to Cloud Functions).
- **Webex** org with **Contact Center** and rights to create or use a **Webex Integration** (client ID and secret); redirect URI must match your function URL + `/callback`.
- **Postman** or **curl** (or your flow’s HTTP client) to call `/init`, test token retrieval, and set headers.
- Optional: upstream [setup video and links](docs/upstream-overview.md).

## Code Scaffold

Runnable sample code lives under **`src/`**:

- **`index.js`** — Cloud Function entry; OAuth callback, `/init`, and token GET/refresh.
- **`package.json`** — `firebase-admin` dependency and Node 18 engine hint.
- **`firestore.rules`** — Deny direct client reads/writes on `tokens/{id}`; deploy with Firebase rules deploy.
- **`env.template`** — Documents **`TOKEN_PASSPHRASE`** and Firestore-held fields (not a `.env` file for GCP; set variables in the function configuration).
- **`LICENSE`** — Upstream MIT (David Finnegan, 2023).

Additional upstream context (video, API JSON examples, `/init` warning, support links) is in [docs/upstream-overview.md](docs/upstream-overview.md).

This is **sample code**: a single shared passphrase protects the token endpoint, **CORS** allows any origin, and there is no per-caller identity or audit trail beyond Cloud logging.

## Deployment Guide

1. **Create** a Firebase/GCP project with **Firestore** and enable the **Cloud Functions** API as required by your console workflow.
2. **Deploy Firestore rules** from [`src/firestore.rules`](src/firestore.rules) using the Firebase CLI or console (replace default rules in dev projects carefully).
3. **Create** an HTTP Cloud Function (1st gen matches the `exports.tokenService` style) with source from [`src/`](src/): upload or connect a repo, set runtime **Node.js 18**, entry point **`tokenService`**, trigger **HTTP** (allow unauthenticated invoke at the Google layer only if you accept that model; the app still requires **`x-token-passphrase`**).
4. **Set** environment variable **`TOKEN_PASSPHRASE`** on the function to a long random string; record the same value for callers. See [`src/env.template`](src/env.template).
5. **Note** the function’s **HTTPS URL** (including any region path). Register **`{functionBaseUrl}/callback`** as the **Redirect URI** on your Webex Integration.
6. **Initialize** a token document: send **GET** `{functionBaseUrl}/init?name=YOUR_TOKEN_NAME` with header **`x-token-passphrase: YOUR_PASSPHRASE`** (adjust if your host/path layout differs; the function must see `req.path === "/init"`). Confirm a Firestore document **`tokens/YOUR_TOKEN_NAME`** appears.
7. **Edit** that document in the **Firebase console** and set **`clientId`**, **`clientSecret`**, and **`redirectUri`** (must match the Integration redirect URI exactly).
8. **Open** the Webex **authorization URL** for your Integration in a browser; set query parameter **`state`** to **`YOUR_TOKEN_NAME`** (not the placeholder `set_state_here`). Sign in and approve; you should see a success JSON from **`{functionBaseUrl}/callback`**.
9. **Test** token retrieval: **GET** `{functionBaseUrl}?name=YOUR_TOKEN_NAME` with header **`x-token-passphrase`** (root path, not `/init` or `/callback`). Expect `{"status":"200","token":"..."}`.
10. **Wire** Webex Contact Center flows or other callers to the same URL and headers; enforce TLS and network controls appropriate to your environment.

<!-- If your Cloud Functions URL layout does not expose `/init` and `/callback` as paths, adjust routing in the Google console (e.g. rewrite rules) or adapt `req.path` checks in code to match your trigger URL pattern. -->

## Known Limitations

- **Not production-hardened:** Shared passphrase only; no per-client identity, OAuth for admin setup is not separately gated, **`Access-Control-Allow-Origin: *`**, and secrets in Firestore require console access control and monitoring.
- **Token expiry:** When the **refresh token** expires, repeat the browser authorization flow. Access tokens are refreshed when less than two hours remain (upstream behavior).
- **`/init` risk:** Running **`/init`** after tokens exist can damage configuration—use only during setup ([upstream note](docs/upstream-overview.md)).
- **License:** Sample derives from MIT-licensed upstream code; see [`src/LICENSE`](src/LICENSE). This Playbook’s repository [LICENSE](../../LICENSE) applies to Playbook packaging and edits.
- **Disclaimer:** This Playbook is a starting point. Webex does not guarantee the functional accuracy of the source code. Test thoroughly before use in a production environment.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Architecture — WxCC token service (Firebase)

HTTP trigger on **Google Cloud Functions** runs `tokenService` ([`src/index.js`](../src/index.js)). **Firebase Admin** reads and writes OAuth state in **Cloud Firestore** (`tokens` collection). Callers use **Webex** OAuth and `https://webexapis.com/v1/access_token` for code exchange and refresh.

```mermaid
sequenceDiagram
participant Admin as AdminBrowser
participant Webex as WebexOAuth
participant GCF as CloudFunction
participant FS as Firestore
participant Caller as FlowOrClient

Admin->>Webex: Authorize with state equals token name
Webex->>GCF: Redirect to callback with code
GCF->>FS: Store access and refresh tokens
Caller->>GCF: GET trigger with name query and x-token-passphrase
GCF->>FS: Read token document
alt access token has under two hours left but refresh valid
GCF->>Webex: POST access_token refresh grant
GCF->>FS: Persist new tokens
end
GCF->>Caller: JSON access token
```

For a self-hosted Express + SQLite alternative, see [wxcc-token-management-sample](../../wxcc-token-management-sample/README.md).
65 changes: 65 additions & 0 deletions playbooks/wxcc-token-service-firebase/docs/upstream-overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Upstream token-service-sample notes

Material adapted from the upstream sample readme so the playbook keeps a single root
[README.md](../README.md). Canonical sample:
[token-service-sample](https://github.com/WebexSamples/webex-contact-center-api-samples/tree/main/token-management-samples/token-service-sample).

## Setup video

[Watch: Token Service setup video](https://app.vidcast.io/share/ed971770-49bb-47e5-96d0-7c920074fd53)

## Related samples

- [token-app-sample](https://github.com/WebexSamples/webex-contact-center-api-samples/tree/main/token-management-samples/token-app-sample) — self-hosted Node pattern (see also the Playbook [wxcc-token-management-sample](../../wxcc-token-management-sample/README.md)).
- [app-auth-sample](https://github.com/WebexSamples/webex-contact-center-api-samples/tree/main/authentication-samples/app-auth-sample) — OAuth with WxCC API.

## Token lifetime (from upstream)

- Access tokens: up to about 12 hours.
- Refresh tokens: up to about 60 days.
- The function returns a valid access token while the refresh token is still valid; after refresh expiry, repeat the browser OAuth step with the same token name in `state`.

## HTTP API shapes

Success:

```json
{
"status": "200",
"token": "example-token-here"
}
```

Error:

```json
{
"status": "500",
"message": "error-message-here"
}
```

## `/init` warning

The `/init` route creates or merges a `tokens` document for the `name` query parameter.
Use it only during setup. Calling it in production after tokens are populated can
overwrite or disrupt configuration—follow the upstream guidance.

## Useful links

- [Webex Contact Center for Developers](https://developer.webex.com/docs/webex-contact-center)

## Upstream disclaimer

The upstream repository states that samples are for demos and learning, not
production-grade solutions, and that security, multi-org design, and operations
should be planned explicitly.

## Support

- [Webex Contact Center APIs Developer Community](https://developer.webex.com/docs/webex-contact-center)
- [How to Ask a Question or Initiate a Discussion](https://community.cisco.com/t5/contact-center/webex-contact-center-apis-developer-community-and-support/m-p/4558270)

## Version history (upstream)

- 1.0.0 — Initial project commit
22 changes: 22 additions & 0 deletions playbooks/wxcc-token-service-firebase/src/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

MIT License

Copyright (c) 2023 David Finnegan

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading