Skip to content

Files

Latest commit

author
Mark Sewell
Jul 18, 2025
051f1de · Jul 18, 2025

History

History
455 lines (339 loc) · 12.4 KB

README.md

File metadata and controls

455 lines (339 loc) · 12.4 KB

Webex Service App Token Getter

Node.js License: MIT Webex

Overview

This application is a Webex Integration that is intended to be used by a developer that manages and owns a Webex Service App. It serves as a companion app to facilitate secure OAuth flows and token management for Webex Service Apps.

Service App Token Getter Architecture

The above diagram outlines a high-level overview of the intended use case for this application. It is a companion app to a Webex Service App that is owned, hosted and used by the Webex Developer.

This Node.js server is designed to:

  • Handle OAuth flows from a Webex Integration
  • Create webhooks for Webex events
  • Manage token exchanges and refreshes
  • Process authorization and token management requests

The server listens for HTTP requests and processes them to handle authorization and token management, making it easier for developers to integrate with Webex Service Apps.

📹 Watch this Vidcast for a demo on getting started!

Table of Contents

Prerequisites

Required Software

  • Node.js (version 14.x or higher)
  • npm (usually comes with Node.js)

Webex Developer Account Requirements

  • Webex Integration with the following scopes:
    • spark:all
    • spark:applications_token
    • application:webhooks_write
    • application:webhooks_read
  • Webex Service App properly configured for your organization

Development Environment

Installation

  1. Clone the repository:

    git clone https://github.com/Joezanini/service_app_token_getter.git
    cd service_app_token_getter
  2. Install dependencies:

    npm install
  3. Set up environment variables:

    cp .env.example .env

    Then edit the .env file with your credentials (see Configuration section).

Configuration

Environment Variables

Create a .env file in the root of your project with the following variables:

# Server Configuration
PORT=3000

# Integration Credentials
INT_CLIENTID=your_integration_client_id
INT_CLIENTSECRET=your_integration_client_secret

# Service App Credentials
SA_CLIENTID=your_service_app_client_id
SA_CLIENTSECRET=your_service_app_client_secret

# OAuth Tokens (initially empty, will be populated automatically)
INT_ACCESSTOKEN=
INT_REFRESHTOKEN=

# Webex API Configuration
TOKEN_ENDPOINT=https://webexapis.com/v1/access_token

# Webhook Configuration
TARGET_URL=https://your-ngrok-url.ngrok.io/webhook

Configuration Details

Variable Description Example
PORT Server port number 3000
INT_CLIENTID Integration Client ID from Webex Developer Portal C1234567890abcdef...
INT_CLIENTSECRET Integration Client Secret from Webex Developer Portal secret123...
SA_CLIENTID Service App Client ID from Webex Developer Portal S1234567890abcdef...
SA_CLIENTSECRET Service App Client Secret from Webex Developer Portal secret456...
TARGET_URL Webhook endpoint URL (must include /webhook path) https://abc123.ngrok.io/webhook

⚠️ Important: Make sure that the TARGET_URL has the /webhook appended as the server is listening at that endpoint.

Usage

Starting the Server

  1. Start the server:

    node server.js
  2. Start with automatic restart (development):

    npm run dev

OAuth Authorization Flow

  1. Access the application:

    • Open your web browser and navigate to the integration registration page
    • Retrieve the authorization URL from the black box on the form

    Authorization URL

  2. Authorize the integration:

    • Open a new incognito tab
    • Paste the authorization URL into the browser
    • Authorize the integration using the developer credentials that registered the integration
    • This will redirect to the redirect URL (e.g., http://localhost:3000/redirect)

Local Development with HTTPS

Since webhooks require HTTPS, you'll need to use a tunneling service for local development:

Using ngrok:

ngrok http 3000

Using Pinggy:

ssh -p 443 -R0:localhost:3000 a.pinggy.io

Update your .env file with the generated HTTPS URL:

TARGET_URL=https://your-tunnel-url.ngrok.io/webhook

Architecture

System Components

Loading
graph TB
    A[Developer] --> B[Webex Integration]
    B --> C[OAuth Authorization]
    C --> D[Service App Token Getter]
    D --> E[Webex Service App]
    D --> F[Webhook Handler]
    F --> G[Token Management]
    G --> H[Webex APIs]

OAuth Flow Sequence

Loading
sequenceDiagram
    participant Dev as Developer
    participant App as Token Getter App
    participant Webex as Webex APIs
    participant SA as Service App
    
    Dev->>App: Start OAuth Flow
    App->>Webex: Authorization Request
    Webex->>Dev: Authorization Code
    Dev->>App: Redirect with Code
    App->>Webex: Exchange Code for Tokens
    Webex->>App: Access & Refresh Tokens
    App->>SA: Authorize Service App
    SA->>App: Webhook Events

API Endpoints

POST /webhook

Handles webhook events from Webex, primarily focusing on Service App authorization events.

Request Body:

{
  "id": "webhook-event-id",
  "name": "authorized",
  "data": {
    "applicationId": "service-app-id",
    "orgId": "organization-id"
  }
}

Response:

{
  "status": "success",
  "message": "Webhook processed successfully"
}

GET /redirect

Handles OAuth redirection and token exchange during the authorization flow.

Query Parameters:

  • code: Authorization code from Webex
  • state: State parameter for security

Response:

  • Redirects to success page or returns error message

Code Overview

Dependencies

Package Purpose Version
http Node.js core module for HTTP server Built-in
axios Promise-based HTTP client ^1.6.0
base64url Base64 encoding/decoding without padding ^3.0.1
url Node.js core module for URL parsing Built-in
dotenv Environment variable management ^16.3.1

Core Functions

exchangeCodeForTokens(code)

Exchanges authorization code for access and refresh tokens.

const tokens = await exchangeCodeForTokens(authorizationCode);

refreshTokens(refreshToken)

Refreshes the access token using the refresh token.

const newTokens = await refreshTokens(currentRefreshToken);

generateApplicationId(clientId)

Generates application ID based on the client ID.

const appId = generateApplicationId(serviceAppClientId);

getOrgId(base64EncodedValue)

Decodes the organization ID from a base64-encoded value.

const orgId = getOrgId(encodedOrgId);

createServiceAppAuthorizedWebhook()

Creates a webhook for the service app authorized event.

await createServiceAppAuthorizedWebhook();

createServiceAppDeauthorizedWebhook()

Creates a webhook for the service app deauthorized event.

await createServiceAppDeauthorizedWebhook();

Server Configuration

The server listens on the port specified in environment variables or defaults to port 3000. It handles the following endpoints:

  • /webhook (POST): Processes webhook events, primarily focusing on the authorized and deauthorized events
  • /redirect (GET): Handles OAuth redirection and token exchange

Docker Support

Building the Docker Image

docker build -t service-app-token-getter .

Running with Docker

docker run -p 3000:3000 --env-file .env service-app-token-getter

Docker Compose

version: '3.8'
services:
  token-getter:
    build: .
    ports:
      - "3000:3000"
    env_file:
      - .env
    restart: unless-stopped

Run with:

docker-compose up -d

Troubleshooting

Common Issues

1. Webhook Creation Errors

Problem: Webhooks fail to create or receive events.

Solution:

  • Ensure TARGET_URL includes the /webhook path
  • Verify your tunnel (ngrok/Pinggy) is running and accessible
  • Check that your Integration has the required scopes

2. Token Exchange Failures

Problem: Authorization code exchange fails.

Solution:

  • Verify Integration credentials in .env file
  • Check that the authorization URL is properly formatted
  • Ensure the redirect URI matches your Integration configuration

3. Webhook Cleanup

Problem: Need to remove webhooks from the integration.

Solution:

  1. Get the webhook ID from the console logs
  2. Use the Webex API to delete the webhook:
    curl -X DELETE "https://webexapis.com/v1/webhooks/{webhookId}" \
         -H "Authorization: Bearer {access_token}"
  3. Alternatively, use the List Webhooks endpoint to find webhook IDs

4. Environment Variable Issues

Problem: Server fails to start due to missing environment variables.

Solution:

  • Ensure all required variables are set in .env
  • Check for typos in variable names
  • Verify .env file is in the project root

Debug Mode

Enable debug logging by setting:

DEBUG=true

Logging

The application logs important events to the console:

  • Token exchanges
  • Webhook creations
  • Authorization events
  • Error messages

Security Considerations

Best Practices

  1. Environment Variables: Never commit .env files to version control
  2. HTTPS: Always use HTTPS for production webhooks
  3. Token Storage: Store tokens securely and refresh them regularly
  4. Access Control: Limit access to your Integration and Service App credentials
  5. Webhook Validation: Validate webhook signatures when available

Production Deployment

For production deployments:

  1. Use a proper reverse proxy (nginx, Apache)
  2. Implement proper logging and monitoring
  3. Set up automated token refresh
  4. Use environment-specific configurations
  5. Implement proper error handling and retry logic

Contributing

We welcome contributions! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch:
    git checkout -b feature/your-feature-name
  3. Make your changes and test thoroughly
  4. Commit your changes:
    git commit -m "Add your feature description"
  5. Push to your branch:
    git push origin feature/your-feature-name
  6. Create a Pull Request

Development Guidelines

  • Follow existing code style and conventions
  • Add comments for complex logic
  • Update documentation for new features
  • Test your changes thoroughly
  • Ensure all dependencies are properly declared

License

This project is licensed under the MIT License. See the LICENSE file for more details.


Additional Resources

Support

For issues and questions:


Happy Coding! 🚀