{"id":19450170,"url":"https://github.com/webexsamples/webex-flask-oauth-example","last_synced_at":"2025-07-23T01:33:32.497Z","repository":{"id":65701741,"uuid":"485537580","full_name":"WebexSamples/webex-flask-oauth-example","owner":"WebexSamples","description":"An example of authenticating an Integration with Webex using Flask with Python 3","archived":false,"fork":false,"pushed_at":"2024-05-07T18:53:53.000Z","size":45,"stargazers_count":4,"open_issues_count":2,"forks_count":7,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-25T03:37:17.102Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WebexSamples.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-25T21:16:42.000Z","updated_at":"2024-08-08T14:28:14.000Z","dependencies_parsed_at":"2024-05-07T19:56:15.780Z","dependency_job_id":null,"html_url":"https://github.com/WebexSamples/webex-flask-oauth-example","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/WebexSamples/webex-flask-oauth-example","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebexSamples%2Fwebex-flask-oauth-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebexSamples%2Fwebex-flask-oauth-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebexSamples%2Fwebex-flask-oauth-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebexSamples%2Fwebex-flask-oauth-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WebexSamples","download_url":"https://codeload.github.com/WebexSamples/webex-flask-oauth-example/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebexSamples%2Fwebex-flask-oauth-example/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266602818,"owners_count":23954696,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-10T16:35:34.279Z","updated_at":"2025-07-23T01:33:32.489Z","avatar_url":"https://github.com/WebexSamples.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Webex Flask OAuth Integration Sample\n\nA comprehensive Flask application demonstrating the complete OAuth 2.0 Authorization Code flow with Webex APIs. This sample showcases secure user authentication, token management, and API integration using a clean web interface.\n\n## 🎯 Features\n\nThis sample demonstrates how to implement OAuth 2.0 with Webex APIs using Flask:\n\n* **OAuth 2.0 Authorization Code Flow** - Standard three-legged OAuth implementation\n* **Token Management** - Access token and refresh token handling\n* **Automatic Token Refresh** - Seamless handling of expired tokens\n* **Webex Rooms API** - Retrieve user's room/space listings\n* **Session Management** - Secure token storage with Flask sessions\n* **State Parameter Validation** - CSRF protection for OAuth flow\n* **Clean Web Interface** - Professional HTML templates with styling\n\n## 📚 Prerequisites\n\n### Software Requirements\n\n- **Python 3.6 or higher**\n- **Flask** web framework\n- **Requests** library for HTTP operations\n\n### Webex Developer Account\n\n- **[Webex Developer Account](https://developer.webex.com/)** - Sign up for free\n- **Webex Integration** configured for OAuth flow\n\n## 🚀 Quick Start\n\n### Install Dependencies\n\nInstall the required Python modules:\n\n```bash\npip install flask requests\n```\n\n### Create Webex Integration\n\n1. **Navigate** to [Webex Developer Portal](https://developer.webex.com)\n2. **Log in** with your Webex account\n3. **Create Integration**:\n   - Go to **My Apps** \u003e **Create New App** \u003e **Integration**\n   - Fill in required details (name, description, icon)\n   - **Redirect URI**: `http://0.0.0.0:10060/oauth` (for local development)\n   - **Scopes**: Select `spark:all` for this sample (fine-tune for production)\n4. **Save** your **Client ID** and **Client Secret**\n\n### Setup and Configuration\n\n1. **Update credentials** in `oauth.py` (lines 23-24):\n   ```python\n   clientID = \"YOUR_CLIENT_ID_HERE\"\n   secretID = \"YOUR_CLIENT_SECRET_HERE\"\n   ```\n\n2. **Update authorization URL** in `templates/index.html`:\n   ```html\n   \u003ca href='YOUR_OAUTH_AUTHORIZATION_URL_HERE'\u003e\n   ```\n\n   **Authorization URL Format:**\n   ```\n   https://webexapis.com/v1/authorize?client_id=YOUR_CLIENT_ID\u0026response_type=code\u0026redirect_uri=http://0.0.0.0:10060/oauth\u0026scope=spark:all\u0026state=1234abcd\n   ```\n\n3. **Start the application**:\n   ```bash\n   python3 oauth.py\n   ```\n\n4. **Access the application**:\n   ```\n   Listening on http://0.0.0.0:10060...\n   ```\n\n5. **Test the OAuth flow**:\n   - Open browser to `http://0.0.0.0:10060`\n   - Click \"GRANT\" to authorize\n   - View your Webex rooms/spaces\n\n## 📁 Project Structure\n\n```\nwebex-flask-oauth-example/\n├── oauth.py                # Main Flask application\n├── static/css/            # CSS styling files\n├── templates/             # HTML templates\n│   ├── index.html         # Landing page with authorization button\n│   ├── granted.html       # Post-authorization page\n│   ├── spaces.html        # Room/space listing display\n│   └── temp.html          # Base template\n├── LICENSE                # Cisco Sample Code License\n└── README.md              # This file\n```\n\n## 🔧 Functionality Overview\n\n### OAuth 2.0 Authorization Code Flow\n\n| Step | Description | Implementation |\n|------|-------------|----------------|\n| **1. Authorization Request** | User clicks GRANT button | `index.html` with authorization URL |\n| **2. User Authentication** | User logs into Webex and authorizes | External Webex authorization |\n| **3. Authorization Code** | Webex redirects with auth code | `/oauth` endpoint receives code |\n| **4. Token Exchange** | Exchange code for access tokens | `get_tokens()` function |\n| **5. API Access** | Use tokens for authenticated requests | `spaces()` endpoint |\n\n### Core Functions\n\n#### Token Exchange\n```python\ndef get_tokens(code):\n    url = \"https://webexapis.com/v1/access_token\"\n    payload = {\n        \"grant_type\": \"authorization_code\",\n        \"client_id\": clientID,\n        \"client_secret\": secretID,\n        \"code\": code,\n        \"redirect_uri\": redirectURI\n    }\n    # Exchange authorization code for tokens\n```\n\n#### Token Refresh\n```python\ndef get_tokens_refresh():\n    url = \"https://webexapis.com/v1/access_token\"\n    payload = {\n        \"grant_type\": \"refresh_token\",\n        \"client_id\": clientID,\n        \"client_secret\": secretID,\n        \"refresh_token\": session['refresh_token']\n    }\n    # Refresh expired access token\n```\n\n#### API Calls with Token Refresh\n```python\ndef spaces():\n    response = api_call()\n    if response.status_code == 401:\n        get_tokens_refresh()  # Auto-refresh on token expiration\n        response = api_call()  # Retry with new token\n    # Process rooms/spaces data\n```\n\n## 🔐 Authentication Flow\n\n### Step-by-Step Process\n\n1. **Landing Page**: User sees \"GRANT INTEGRATION ACCESS\" button\n2. **Authorization**: Clicking GRANT redirects to Webex authorization server\n3. **User Login**: User authenticates with Webex credentials\n4. **Authorization**: User approves requested scopes\n5. **Callback**: Webex redirects back with authorization code\n6. **Token Exchange**: App exchanges code for access and refresh tokens\n7. **API Access**: User can now access their Webex data\n\n### Security Features\n\n- **State Parameter**: CSRF protection with hardcoded state value\n- **Secure Sessions**: Tokens stored in Flask session with random secret key\n- **Automatic Refresh**: Expired tokens automatically refreshed\n- **Scope Validation**: OAuth scopes properly configured\n\n## 📡 API Integration\n\n### Webex Rooms API\n\nThe application demonstrates API integration by fetching the user's rooms:\n\n```python\ndef api_call():\n    accessToken = session['oauth_token']\n    url = \"https://webexapis.com/v1/rooms\"\n    headers = {\n        'accept': 'application/json',\n        'Content-Type': 'application/json',\n        'Authorization': f'Bearer {accessToken}'\n    }\n    response = requests.get(url=url, headers=headers)\n    return response\n```\n\n### Error Handling\n\nComprehensive error handling with automatic token refresh:\n\n```python\ndef spaces():\n    response = api_call()\n    # Check for unauthorized response\n    if response.status_code == 401:\n        get_tokens_refresh()    # Refresh tokens\n        response = api_call()   # Retry API call\n    \n    # Process successful response\n    rooms = response.json()['items']\n    space_titles = [room['title'] for room in rooms]\n    return render_template(\"spaces.html\", spaces=space_titles)\n```\n\n## 🎨 User Interface\n\n### Flask Templates\n\nThe application uses Jinja2 templates with inheritance:\n\n- **`temp.html`**: Base template with common styling\n- **`index.html`**: Authorization page with GRANT button\n- **`granted.html`**: Success page with SPACES button\n- **`spaces.html`**: List of user's rooms/spaces\n\n### Template Structure\n\n```html\n\u003c!-- index.html --\u003e\n{% extends \"temp.html\" %}\n{% block content %}\n\u003ch1\u003eGRANT INTEGRATION ACCESS\u003c/h1\u003e\n\u003cdiv class='center'\u003e\n    \u003ca href='OAUTH_URL_HERE'\u003e\n        \u003cdiv class='button' style='width:512px;'\u003eGRANT\u003c/div\u003e\n    \u003c/a\u003e\n\u003c/div\u003e\n{% endblock %}\n```\n\n### User Experience Flow\n\n1. **Authorization Page**: Clean interface with prominent GRANT button\n2. **Webex Login**: External Webex authentication\n3. **Success Page**: Confirmation with SPACES button\n4. **Data Display**: List of user's rooms/spaces\n\n## 🔧 Configuration\n\n### Required Configuration Variables\n\n| Variable | Location | Description | Example |\n|----------|----------|-------------|---------|\n| `clientID` | `oauth.py` line 23 | Integration Client ID | `C1234567890abcdef...` |\n| `secretID` | `oauth.py` line 24 | Integration Client Secret | `secret123...` |\n| `redirectURI` | `oauth.py` line 25 | OAuth callback URL | `http://0.0.0.0:10060/oauth` |\n| Authorization URL | `index.html` | Webex OAuth endpoint | See format below |\n\n### Authorization URL Format\n\n```\nhttps://webexapis.com/v1/authorize?\nclient_id=YOUR_CLIENT_ID\u0026\nresponse_type=code\u0026\nredirect_uri=http://0.0.0.0:10060/oauth\u0026\nscope=spark:all\u0026\nstate=1234abcd\n```\n\n### Flask Application Settings\n\n```python\napp = Flask(__name__)\napp.secret_key = os.urandom(24)  # Secure session key\napp.run(\"0.0.0.0\", port=10060, debug=False)  # Server configuration\n```\n\n## 🌐 Production Considerations\n\n### Security Best Practices\n\n1. **Environment Variables**: Store credentials securely\n   ```python\n   import os\n   clientID = os.getenv('WEBEX_CLIENT_ID')\n   secretID = os.getenv('WEBEX_CLIENT_SECRET')\n   ```\n\n2. **HTTPS**: Use HTTPS in production\n   ```python\n   redirectURI = \"https://yourdomain.com/oauth\"\n   ```\n\n3. **Dynamic State**: Generate random state parameter\n   ```python\n   import secrets\n   state = secrets.token_urlsafe(32)\n   ```\n\n4. **Secure Token Storage**: Use database instead of sessions\n   ```python\n   # Replace Flask sessions with secure database storage\n   # Implement proper token encryption\n   ```\n\n### Production Deployment\n\n```python\n# Production configuration\nif __name__ == '__main__':\n    port = int(os.environ.get('PORT', 10060))\n    app.run(host='0.0.0.0', port=port, debug=False)\n```\n\n### Error Handling Enhancement\n\n```python\ndef get_tokens(code):\n    try:\n        response = requests.post(url=url, data=payload, headers=headers, timeout=30)\n        response.raise_for_status()\n        results = response.json()\n        # Process tokens\n    except requests.exceptions.RequestException as e:\n        logger.error(f\"Token exchange failed: {e}\")\n        # Handle error appropriately\n```\n\n## 🔧 Development\n\n### Local Development Setup\n\n1. **Virtual Environment**:\n   ```bash\n   python -m venv venv\n   source venv/bin/activate  # On Windows: venv\\Scripts\\activate\n   pip install flask requests\n   ```\n\n2. **Development Mode**:\n   ```python\n   app.run(\"0.0.0.0\", port=10060, debug=True)\n   ```\n\n### Adding Features\n\nExample: Adding user profile information:\n\n```python\n@app.route(\"/profile\")\ndef profile():\n    accessToken = session['oauth_token']\n    url = \"https://webexapis.com/v1/people/me\"\n    headers = {'Authorization': f'Bearer {accessToken}'}\n    \n    response = requests.get(url, headers=headers)\n    if response.status_code == 401:\n        get_tokens_refresh()\n        response = requests.get(url, headers=headers)\n    \n    user_info = response.json()\n    return render_template(\"profile.html\", user=user_info)\n```\n\n### Testing the Flow\n\n1. **Start application**: `python3 oauth.py`\n2. **Open browser**: `http://0.0.0.0:10060`\n3. **Click GRANT**: Initiates OAuth flow\n4. **Authorize**: Log in and approve access\n5. **View spaces**: See your Webex rooms/spaces\n\n## 🔗 Related Resources\n\n- [Webex Developer Portal](https://developer.webex.com/)\n- [OAuth 2.0 Authorization Code Flow](https://tools.ietf.org/html/rfc6749#section-4.1)\n- [Webex API Documentation](https://developer.webex.com/docs/api/v1/)\n- [Flask Documentation](https://flask.palletsprojects.com/)\n- [Integration Management](https://developer.webex.com/my-apps)\n\n## 🤝 Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Test thoroughly with Webex integration\n5. Submit a pull request\n\n## 📄 License\n\nThis project is licensed under the **Cisco Sample Code License**.\n\n### License Summary\n\n- ✅ **Permitted**: Copy, modify, and redistribute for use with Cisco products\n- ❌ **Prohibited**: Use independent of Cisco products or to compete with Cisco\n- ℹ️ **Warranty**: Provided \"as is\" without warranty\n- ℹ️ **Support**: Not supported by Cisco TAC\n\nSee the [LICENSE](LICENSE) file for full license terms.\n\n## 🆘 Support\n\n- Create an issue in this repository\n- Visit [Webex Developer Support](https://developer.webex.com/support)\n- Join the [Webex Developer Community](https://developer.webex.com/community)\n\n---\n\n**Ready to integrate OAuth 2.0 with Webex!** 🚀🔐\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebexsamples%2Fwebex-flask-oauth-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebexsamples%2Fwebex-flask-oauth-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebexsamples%2Fwebex-flask-oauth-example/lists"}