├── python-flask ├── .gitignore ├── requirements.txt ├── config.py ├── README.md └── run.py ├── node-express ├── package.json ├── config.js ├── README.md └── app.js ├── php ├── config.php ├── index.php ├── connected.php └── README.md ├── .gitignore ├── LICENSE └── README.md /python-flask/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | venv 3 | -------------------------------------------------------------------------------- /python-flask/requirements.txt: -------------------------------------------------------------------------------- 1 | Jinja2>=3.1.3 2 | MarkupSafe>=2.1.5 3 | Werkzeug>=3.0.1 4 | itsdangerous>=2.1.2 5 | requests>=2.31.0 6 | flask>=2.3.2 -------------------------------------------------------------------------------- /python-flask/config.py: -------------------------------------------------------------------------------- 1 | wpcc_consts = { 2 | "client_id": 1, # TODO 3 | "client_secret": "your-client-secret", # TODO 4 | "login_url": "http://localhost:5001/", # TODO 5 | "redirect_url": "http://localhost:5001/connected", # TODO 6 | "request_token_url": "https://public-api.wordpress.com/oauth2/token", 7 | "authenticate_url": "https://public-api.wordpress.com/oauth2/authenticate" 8 | } 9 | -------------------------------------------------------------------------------- /node-express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wordpress-express", 3 | "description": "WordPress.com Connect", 4 | "version": "0.0.1", 5 | "private": true, 6 | "scripts": { 7 | "start": "node app.js" 8 | }, 9 | "dependencies": { 10 | "cookie-parser": "^1.4.7", 11 | "dotenv": "^16.5.0", 12 | "express": "^5.1.0", 13 | "express-session": "^1.18.1", 14 | "request": "^2.88.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /node-express/config.js: -------------------------------------------------------------------------------- 1 | // Replace the TODO values with the values shown on your app's Manage Settings page: https://developer.wordpress.com/apps/ 2 | // For more details, see the https://developer.wordpress.com/docs/oauth2/ 3 | 4 | module.exports = { 5 | client_id: 1, //TODO 6 | client_secret: "your-client-secret", //TODO 7 | login_url: "http://localhost:3000/", //TODO 8 | redirect_url: "http://localhost:3000/connected", //TODO 9 | request_token_url: "https://public-api.wordpress.com/oauth2/token", 10 | authenticate_url: "https://public-api.wordpress.com/oauth2/authenticate", 11 | }; 12 | -------------------------------------------------------------------------------- /php/config.php: -------------------------------------------------------------------------------- 1 | 'code', 16 | 'client_id' => CLIENT_ID, 17 | 'state' => $_SESSION['wpcc_state'], 18 | 'redirect_uri' => REDIRECT_URL 19 | )); 20 | 21 | echo '

Connect using your WordPress.com account

'; 22 | echo ''; 23 | -------------------------------------------------------------------------------- /python-flask/README.md: -------------------------------------------------------------------------------- 1 | # WordPress.com Connect Example (Flask) 2 | 3 | This is an example Flask application demonstrating how to connect with WordPress.com using OAuth2. 4 | 5 | ## Setup & Run Instructions 6 | 7 | 1. **Clone this repository and navigate to the `flask` directory:** 8 | ```sh 9 | cd flask 10 | ``` 11 | 12 | 2. **Create and activate a virtual environment:** 13 | ```sh 14 | python3 -m venv venv 15 | source venv/bin/activate 16 | ``` 17 | 18 | 3. **Install dependencies:** 19 | ```sh 20 | pip install -r requirements.txt 21 | ``` 22 | 23 | 4. **Configure your WordPress.com credentials:** 24 | - Edit `config.py` and set your `client_id` and `client_secret`. 25 | 26 | 5. **Run the Flask app:** 27 | ```sh 28 | python run.py 29 | ``` 30 | 31 | 6. **Open your browser and visit:** 32 | [http://localhost:5001/](http://localhost:5001/) 33 | 34 | --- 35 | 36 | **Note:** 37 | - If you change dependencies, re-run the install command. 38 | - If you encounter import errors, ensure your virtual environment is activated and all dependencies are installed. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /php/connected.php: -------------------------------------------------------------------------------- 1 | CLIENT_ID, 26 | 'redirect_uri' => REDIRECT_URL, 27 | 'client_secret' => CLIENT_SECRET, 28 | 'code' => $code, 29 | 'grant_type' => 'authorization_code' 30 | )); 31 | 32 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 33 | $auth = curl_exec($curl); 34 | 35 | // The JSON response can be decoded to an object containing the access_token 36 | // that you will use to query the users profile information. 37 | $secret = json_decode($auth); 38 | 39 | // TODO: In a real app, you'll likely want to store the returned token so that 40 | // you can continue to make authenticated requests. 41 | echo 'Access Token: ' . $secret->access_token . '
'; 42 | echo 'This token can be used to request more info about the user to the endpoint: https://developer.wordpress.com/docs/api/1.1/get/me
'; 43 | echo 'Connection successful!'; 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WordPress.com Connect Examples 2 | ====================== 3 | 4 | Code Examples for Implementing WordPress.com Connect 5 | 6 | ### Instructions 7 | 8 | These examples require minor changes to get working. The full instructions for getting a PHP app running are on [developer.wordpress.com](http://developer.wordpress.com/docs/wpcc/). 9 | 10 | These instructions assume you know how to run a website for your chosen framework: PHP (start a webserver), Node.js (run npm install), etc. 11 | 12 | 1. Log in to [WordPress.com](http://wordpress.com) 13 | 2. Create a new WPCC application: [developer.wordpress.com/apps/](https://developer.wordpress.com/apps/). You can change these settings at any time. 14 | 3. Adjust the following values (in the proper config file) to match the ones in your WPCC application: 15 | - Client ID 16 | - Client Secret 17 | - Login URL 18 | - Redirect URL 19 | 4. Start your server and log in. 20 | 5. Profit! 21 | 22 | Storing and using the access token is an exercise left for the developer. 23 | 24 | ### Current Demos 25 | 26 | | Demo | Language | Framework | Description | Author | 27 | |---------------------------------|------------|-----------------|-----------------------------------|-------------------------------------| 28 | | [`/php`](php) | PHP | N/A | Auth via wp.com and token display | [Automattic](http://automattic.com) | 29 | | [`/node-express`](node-express) | Javascript | Node.js Express | Auth via wp.com and token display | [Automattic](http://automattic.com) | 30 | | [`/python-flask`](python-flask) | Python | Flask | Auth via wp.com and token display | [Automattic](http://automattic.com) | 31 | 32 | 33 | ### Where is the demo for Framework X? 34 | 35 | If you implement a framework we don't have, we'd love to include it in this project. Just submit a pull request. 36 | -------------------------------------------------------------------------------- /php/README.md: -------------------------------------------------------------------------------- 1 | # WordPress.com Connect PHP Demo 2 | 3 | This is a simple PHP example demonstrating how to implement WordPress.com Connect (OAuth2 authentication) in your application. 4 | 5 | ## Prerequisites 6 | 7 | - PHP 7.0 or higher 8 | - A local web server (e.g., [PHP built-in server](https://www.php.net/manual/en/features.commandline.webserver.php), Apache, or Nginx) 9 | - A [WordPress.com Developer Application](https://developer.wordpress.com/apps/) 10 | 11 | ## Setup Instructions 12 | 13 | 1. **Clone this repository** (if you haven't already): 14 | ```sh 15 | git clone https://github.com/Automattic/wpcom-connect-examples.git 16 | cd wpcom-connect-examples/php 17 | ``` 18 | 19 | 2. **Register a new application** at [WordPress.com Developer Console](https://developer.wordpress.com/apps/): 20 | - Set the **Redirect URL** to: `http://localhost:8000/connected.php` 21 | - Note your **Client ID** and **Client Secret**. 22 | 23 | 3. **Configure your credentials:** 24 | - Open `config.php` in this folder. 25 | - Replace the values for `CLIENT_ID` and `CLIENT_SECRET` with those from your app's settings. 26 | - Adjust `LOGIN_URL` and `REDIRECT_URL` if you use a different port or domain. 27 | 28 | 4. **Start the PHP built-in server:** 29 | ```sh 30 | php -S localhost:8000 31 | ``` 32 | - This will serve the demo at [http://localhost:8000](http://localhost:8000) 33 | 34 | 5. **Test the demo:** 35 | - Open [http://localhost:8000/index.php](http://localhost:8000/index.php) in your browser. 36 | - Click the "Connect using your WordPress.com account" button. 37 | - Authorize the app and you should see a "Connection successful!" message. 38 | 39 | ## Notes 40 | 41 | - This demo is for educational purposes. In a real application, you should securely store the access token and handle errors appropriately. 42 | - If you change the port or domain, update `LOGIN_URL` and `REDIRECT_URL` in `config.php` and in your WordPress.com app settings. 43 | - For more details, see the [official documentation](https://developer.wordpress.com/docs/oauth2/). -------------------------------------------------------------------------------- /node-express/README.md: -------------------------------------------------------------------------------- 1 | # WordPress.com Connect Node/Express.js Demo 2 | 3 | This is a simple Node.js/Express.js example demonstrating how to implement WordPress.com Connect (OAuth2 authentication) in your application. 4 | 5 | ## Prerequisites 6 | 7 | - Node.js (v14 or higher recommended) 8 | - npm (comes with Node.js) 9 | - A [WordPress.com Developer Application](https://developer.wordpress.com/apps/) 10 | 11 | ## Setup Instructions 12 | 13 | 1. **Clone this repository** (if you haven't already): 14 | ```sh 15 | git clone https://github.com/Automattic/wpcom-connect-examples.git 16 | cd wpcom-connect-examples/express.js 17 | ``` 18 | 19 | 2. **Register a new application** at [WordPress.com Developer Console](https://developer.wordpress.com/apps/): 20 | - Set the **Redirect URL** to: `http://localhost:3000/connected` 21 | - Note your **Client ID** and **Client Secret**. 22 | 23 | 3. **Configure your credentials:** 24 | - Open `config.js` in this folder. 25 | - Replace the `client_id`, `client_secret`, `login_url`, and `redirect_url` values with those from your app's settings. 26 | - Adjust `login_url` and `redirect_url` if you use a different port or domain. 27 | 28 | 4. **Install dependencies:** 29 | ```sh 30 | npm install 31 | ``` 32 | 33 | 5. **Start the server:** 34 | ```sh 35 | npm start 36 | ``` 37 | - This will serve the demo at [http://localhost:3000](http://localhost:3000) 38 | 39 | 6. **Test the demo:** 40 | - Open [http://localhost:3000](http://localhost:3000) in your browser. 41 | - Click the "Connect with WordPress.com" button. 42 | - Authorize the app and you should see a "Connected to WordPress.com!" message. 43 | 44 | ## Notes 45 | 46 | - This demo is for educational purposes. In a real application, you should securely store the access token and handle errors appropriately. 47 | - If you change the port or domain, update `login_url` and `redirect_url` in `config.js` and in your WordPress.com app settings. 48 | - You can set a custom session secret by defining the `SESSION_SECRET` environment variable. 49 | - For more details, see the [official documentation](https://developer.wordpress.com/docs/oauth2/). -------------------------------------------------------------------------------- /python-flask/run.py: -------------------------------------------------------------------------------- 1 | # Example WordPress.com Connect 2 | 3 | import requests 4 | import string 5 | import random 6 | import hashlib 7 | import urllib.parse 8 | from flask import abort, redirect, url_for 9 | from flask import make_response 10 | from flask import request 11 | from flask import Flask 12 | from config import wpcc_consts 13 | app = Flask(__name__) 14 | 15 | 16 | @app.route("/") 17 | def login(): 18 | state = ''.join(random.choice(string.ascii_uppercase + string.digits) 19 | for x in range(30)) 20 | params = { 21 | "response_type": "code", 22 | "client_id": wpcc_consts['client_id'], 23 | "state": state, 24 | "redirect_uri": wpcc_consts['redirect_url'] 25 | } 26 | wpcc_url = wpcc_consts['authenticate_url'] + \ 27 | '?' + urllib.parse.urlencode(params) 28 | resp = make_response( 29 | '

Connect to WordPress.com

' 32 | ) 33 | 34 | resp.set_cookie('wpcc_state', state) 35 | return resp 36 | 37 | 38 | @app.route("/connected") 39 | def connected(): 40 | app.logger.info("Connected page accessed") 41 | code = request.args.get('code') 42 | 43 | if not code: 44 | return redirect(url_for('login')) 45 | 46 | state = request.args.get('state') 47 | if not state: 48 | app.logger.warning('State parameter missing in callback URL') 49 | return 'Warning! State variable missing after authentication' 50 | 51 | wpcc_state = request.cookies.get('wpcc_state') 52 | if not wpcc_state: 53 | app.logger.warning('wpcc_state cookie missing') 54 | return 'Warning! State cookie missing. Authentication attempt may have been compromised.' 55 | 56 | if state != wpcc_state: 57 | app.logger.warning( 58 | 'State mismatch: received %s, expected %s', state, wpcc_state) 59 | return 'Warning! State mismatch. Authentication attempt may have been compromised.' 60 | 61 | # Optionally, clear the state cookie after use 62 | payload = { 63 | "client_id": wpcc_consts['client_id'], 64 | "redirect_uri": wpcc_consts['redirect_url'], 65 | "client_secret": wpcc_consts['client_secret'], 66 | "code": code, # The code from the previous request 67 | "grant_type": 'authorization_code' 68 | } 69 | r = requests.post(wpcc_consts['request_token_url'], data=payload) 70 | if 200 == r.status_code: 71 | token_data = r.json() 72 | access_token = token_data.get('access_token', 'No token found') 73 | resp = make_response( 74 | f'' 75 | f'

Connected to WordPress.com!

' 76 | f'

Access Token: ' 77 | f'{access_token}

' 78 | f'

This token can be used to request more info about the user to the endpoint: ' 79 | f'https://developer.wordpress.com/docs/api/1.1/get/me

' 80 | f'

Connection successful!

' 81 | f'' 82 | ) 83 | resp.set_cookie('wpcc_state', '', expires=0) 84 | return resp 85 | 86 | return 'Error: ' + r.text 87 | 88 | 89 | if __name__ == "__main__": 90 | app.debug = True 91 | app.run(host='localhost', port=5001) 92 | -------------------------------------------------------------------------------- /node-express/app.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const express = require('express'); 3 | const request = require('request'); 4 | const cookieParser = require('cookie-parser'); 5 | const session = require('express-session'); 6 | const crypto = require('crypto'); 7 | const wpcc_consts = require('./config.js'); 8 | 9 | const app = express(); 10 | const session_secret = process.env.SESSION_SECRET || 'FixMeBuildBetterSecretThanThis'; 11 | 12 | app.use(cookieParser()); 13 | app.use( 14 | session({ 15 | secret: session_secret, 16 | resave: false, 17 | saveUninitialized: true, 18 | cookie: { httpOnly: true, secure: false }, // Set secure: true if using HTTPS 19 | }) 20 | ); 21 | 22 | // Helper to build query string 23 | function buildQuery(params) { 24 | return Object.entries(params) 25 | .map(([key, val]) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`) 26 | .join('&'); 27 | } 28 | 29 | app.get('/', (req, res) => { 30 | // Generate a cryptographically secure random state 31 | const state = crypto.randomBytes(16).toString('hex'); 32 | req.session.wpcc_state = state; 33 | 34 | const params = { 35 | response_type: 'code', 36 | client_id: wpcc_consts.client_id, 37 | state, 38 | redirect_uri: wpcc_consts.redirect_url, 39 | }; 40 | const wpcc_url = `${wpcc_consts.authenticate_url}?${buildQuery(params)}`; 41 | 42 | const body = ` 43 | 44 | 45 | 46 | 47 | Connect to WordPress.com 48 | 49 | 50 |

Connect to WordPress.com

51 | Connect with WordPress.com 52 | 53 | `; 54 | 55 | res.status(200).send(body); 56 | }); 57 | 58 | app.get('/connected', (req, res) => { 59 | const { code, state } = req.query; 60 | if (code) { 61 | if (!state) { 62 | res.status(400).send('Warning! State variable missing after authentication'); 63 | return; 64 | } 65 | if (state !== req.session.wpcc_state) { 66 | res.status(400).send('Warning! State mismatch. Authentication attempt may have been compromised.'); 67 | return; 68 | } 69 | 70 | const post_data = { 71 | form: { 72 | client_id: wpcc_consts.client_id, 73 | redirect_uri: wpcc_consts.redirect_url, 74 | client_secret: wpcc_consts.client_secret, 75 | code, 76 | grant_type: 'authorization_code', 77 | }, 78 | }; 79 | 80 | request.post( 81 | wpcc_consts.request_token_url, 82 | post_data, 83 | (error, response, body) => { 84 | if (!error && response.statusCode === 200) { 85 | // TODO: In a real app, store the returned token securely 86 | const secret = JSON.parse(body); 87 | const html = `Access Token: ${secret.access_token}
88 | This token can be used to request more info about the user to the endpoint: https://developer.wordpress.com/docs/api/1.1/get/me
89 | Connection successful!`; 90 | res.status(200).send(html); 91 | } else { 92 | // Avoid leaking sensitive info in production 93 | res.status(response ? response.statusCode : 500).send('ERROR: ' + (body || error.message)); 94 | } 95 | } 96 | ); 97 | } else { 98 | // Redirect errors or cancelled requests back to login page 99 | res.redirect(303, wpcc_consts.login_url); 100 | } 101 | }); 102 | 103 | const PORT = process.env.PORT || 3000; 104 | app.listen(PORT, () => { 105 | console.log(`Listening on port ${PORT}`); 106 | }); 107 | --------------------------------------------------------------------------------