A 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.
This sample demonstrates how to implement OAuth 2.0 with Webex APIs using Flask:
- OAuth 2.0 Authorization Code Flow - Standard three-legged OAuth implementation
- Token Management - Access token and refresh token handling
- Automatic Token Refresh - Seamless handling of expired tokens
- Webex Rooms API - Retrieve user's room/space listings
- Session Management - Secure token storage with Flask sessions
- State Parameter Validation - CSRF protection for OAuth flow
- Clean Web Interface - Professional HTML templates with styling
- Python 3.6 or higher
- Flask web framework
- Requests library for HTTP operations
- Webex Developer Account - Sign up for free
- Webex Integration configured for OAuth flow
Install the required Python modules:
pip install flask requests- Navigate to Webex Developer Portal
- Log in with your Webex account
- Create Integration:
- Go to My Apps > Create New App > Integration
- Fill in required details (name, description, icon)
- Redirect URI:
http://0.0.0.0:10060/oauth(for local development) - Scopes: Select
spark:allfor this sample (fine-tune for production)
- Save your Client ID and Client Secret
-
Update credentials in
oauth.py(lines 23-24):clientID = "YOUR_CLIENT_ID_HERE" secretID = "YOUR_CLIENT_SECRET_HERE"
-
Update authorization URL in
templates/index.html:<a href='YOUR_OAUTH_AUTHORIZATION_URL_HERE'>
Authorization URL Format:
https://webexapis.com/v1/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=http://0.0.0.0:10060/oauth&scope=spark:all&state=1234abcd -
Start the application:
python3 oauth.py
-
Access the application:
Listening on http://0.0.0.0:10060... -
Test the OAuth flow:
- Open browser to
http://0.0.0.0:10060 - Click "GRANT" to authorize
- View your Webex rooms/spaces
- Open browser to
webex-flask-oauth-example/
βββ oauth.py # Main Flask application
βββ static/css/ # CSS styling files
βββ templates/ # HTML templates
β βββ index.html # Landing page with authorization button
β βββ granted.html # Post-authorization page
β βββ spaces.html # Room/space listing display
β βββ temp.html # Base template
βββ LICENSE # Cisco Sample Code License
βββ README.md # This file
| Step | Description | Implementation |
|---|---|---|
| 1. Authorization Request | User clicks GRANT button | index.html with authorization URL |
| 2. User Authentication | User logs into Webex and authorizes | External Webex authorization |
| 3. Authorization Code | Webex redirects with auth code | /oauth endpoint receives code |
| 4. Token Exchange | Exchange code for access tokens | get_tokens() function |
| 5. API Access | Use tokens for authenticated requests | spaces() endpoint |
def get_tokens(code):
url = "https://webexapis.com/v1/access_token"
payload = {
"grant_type": "authorization_code",
"client_id": clientID,
"client_secret": secretID,
"code": code,
"redirect_uri": redirectURI
}
# Exchange authorization code for tokensdef get_tokens_refresh():
url = "https://webexapis.com/v1/access_token"
payload = {
"grant_type": "refresh_token",
"client_id": clientID,
"client_secret": secretID,
"refresh_token": session['refresh_token']
}
# Refresh expired access tokendef spaces():
response = api_call()
if response.status_code == 401:
get_tokens_refresh() # Auto-refresh on token expiration
response = api_call() # Retry with new token
# Process rooms/spaces data- Landing Page: User sees "GRANT INTEGRATION ACCESS" button
- Authorization: Clicking GRANT redirects to Webex authorization server
- User Login: User authenticates with Webex credentials
- Authorization: User approves requested scopes
- Callback: Webex redirects back with authorization code
- Token Exchange: App exchanges code for access and refresh tokens
- API Access: User can now access their Webex data
- State Parameter: CSRF protection with hardcoded state value
- Secure Sessions: Tokens stored in Flask session with random secret key
- Automatic Refresh: Expired tokens automatically refreshed
- Scope Validation: OAuth scopes properly configured
The application demonstrates API integration by fetching the user's rooms:
def api_call():
accessToken = session['oauth_token']
url = "https://webexapis.com/v1/rooms"
headers = {
'accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': f'Bearer {accessToken}'
}
response = requests.get(url=url, headers=headers)
return responseComprehensive error handling with automatic token refresh:
def spaces():
response = api_call()
# Check for unauthorized response
if response.status_code == 401:
get_tokens_refresh() # Refresh tokens
response = api_call() # Retry API call
# Process successful response
rooms = response.json()['items']
space_titles = [room['title'] for room in rooms]
return render_template("spaces.html", spaces=space_titles)The application uses Jinja2 templates with inheritance:
temp.html: Base template with common stylingindex.html: Authorization page with GRANT buttongranted.html: Success page with SPACES buttonspaces.html: List of user's rooms/spaces
<!-- index.html -->
{% extends "temp.html" %}
{% block content %}
<h1>GRANT INTEGRATION ACCESS</h1>
<div class='center'>
<a href='OAUTH_URL_HERE'>
<div class='button' style='width:512px;'>GRANT</div>
</a>
</div>
{% endblock %}- Authorization Page: Clean interface with prominent GRANT button
- Webex Login: External Webex authentication
- Success Page: Confirmation with SPACES button
- Data Display: List of user's rooms/spaces
| Variable | Location | Description | Example |
|---|---|---|---|
clientID |
oauth.py line 23 |
Integration Client ID | C1234567890abcdef... |
secretID |
oauth.py line 24 |
Integration Client Secret | secret123... |
redirectURI |
oauth.py line 25 |
OAuth callback URL | http://0.0.0.0:10060/oauth |
| Authorization URL | index.html |
Webex OAuth endpoint | See format below |
https://webexapis.com/v1/authorize?
client_id=YOUR_CLIENT_ID&
response_type=code&
redirect_uri=http://0.0.0.0:10060/oauth&
scope=spark:all&
state=1234abcd
app = Flask(__name__)
app.secret_key = os.urandom(24) # Secure session key
app.run("0.0.0.0", port=10060, debug=False) # Server configuration-
Environment Variables: Store credentials securely
import os clientID = os.getenv('WEBEX_CLIENT_ID') secretID = os.getenv('WEBEX_CLIENT_SECRET')
-
HTTPS: Use HTTPS in production
redirectURI = "https://yourdomain.com/oauth"
-
Dynamic State: Generate random state parameter
import secrets state = secrets.token_urlsafe(32)
-
Secure Token Storage: Use database instead of sessions
# Replace Flask sessions with secure database storage # Implement proper token encryption
# Production configuration
if __name__ == '__main__':
port = int(os.environ.get('PORT', 10060))
app.run(host='0.0.0.0', port=port, debug=False)def get_tokens(code):
try:
response = requests.post(url=url, data=payload, headers=headers, timeout=30)
response.raise_for_status()
results = response.json()
# Process tokens
except requests.exceptions.RequestException as e:
logger.error(f"Token exchange failed: {e}")
# Handle error appropriately-
Virtual Environment:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate pip install flask requests
-
Development Mode:
app.run("0.0.0.0", port=10060, debug=True)
Example: Adding user profile information:
@app.route("/profile")
def profile():
accessToken = session['oauth_token']
url = "https://webexapis.com/v1/people/me"
headers = {'Authorization': f'Bearer {accessToken}'}
response = requests.get(url, headers=headers)
if response.status_code == 401:
get_tokens_refresh()
response = requests.get(url, headers=headers)
user_info = response.json()
return render_template("profile.html", user=user_info)- Start application:
python3 oauth.py - Open browser:
http://0.0.0.0:10060 - Click GRANT: Initiates OAuth flow
- Authorize: Log in and approve access
- View spaces: See your Webex rooms/spaces
- Webex Developer Portal
- OAuth 2.0 Authorization Code Flow
- Webex API Documentation
- Flask Documentation
- Integration Management
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly with Webex integration
- Submit a pull request
This project is licensed under the Cisco Sample Code License.
- β Permitted: Copy, modify, and redistribute for use with Cisco products
- β Prohibited: Use independent of Cisco products or to compete with Cisco
- βΉοΈ Warranty: Provided "as is" without warranty
- βΉοΈ Support: Not supported by Cisco TAC
See the LICENSE file for full license terms.
- Create an issue in this repository
- Visit Webex Developer Support
- Join the Webex Developer Community
Ready to integrate OAuth 2.0 with Webex! ππ