Linking a user account to an external phpBB forum
This article will show you how to verify a user’s identity by letting them associate their account with an external third party phpBB account. I used Python and Flask to achieve this, however any language and framework should work, and shouldn’t be too hard to port to.
I wrote a Python library to parse phpBB profiles which I will be using throughout this tutorial.
First, you’ll need to install some packages:
pip install beautifulsoup4 phpbb-parser
I’m using Flask, Flask-User and Flask-SQLAlchemy.
pip install flask flask-user Flask-SQLAlchemy
You need to add a forum
field to the user model:
class User(db.Model, UserMixin):
# ...
# Forum
forum = db.Column(db.String(100), nullable=True)
Basic Idea: Forum signature linking #
- Server generates random token.
- User adds token to signature.
- User gives forum username.
- Server looks up signature from forum username.
- If match, link accounts
Template: link_forum.html #
This is a page that gives the user the option to link to a forum.
<div class="box box_grey">
<h2>Link forum account</h2>
<form method="post" action="{{ url_for('link_forum_page') }}">
<p>
Enter your forum username here:
</p>
<input type="text" name="forum_username"
value="{{ forum_username }}"
required placeholder="Forum username">
<p>
Go to
<a href="{{ forum_url }}/ucp.php?i=profile&mode=signature">
User Control Panel > Profile > Edit signature
</a>
</p>
<p>
Paste this into your signature:
</p>
<input type="text" value="{{ key }}" readonly size=32>
<p>
Click next so we can check it.
</p>
<p>
Don't worry, you can remove it after this is done.
</p>
<input type="submit" value="Next">
</form>
</div>
Token cache #
I used a memcache in order to temporarily associate an IP with a random token
from werkzeug.contrib.cache import SimpleCache
cache = SimpleCache()
View: link_forum_page #
# Project components
from app import app
from models import *
# Dependencies
from flask import *
from flask_user import *
import phpbb_parser as parser
# GET link_forum_page
def link_forum_get():
# Used to automatically fill out the forms in the template with a forum username
forum_username = request.args.get("user") or ""
# Create random token
import uuid
key = uuid.uuid4().hex
cache.set("forum_claim_key_" + request.remote_addr, key, 5*60)
return render_template('link_forum.html', key=key,
forum_username=forum_username, forum_url="https://example.com")
# POST link_forum_page
def link_forum_post():
forum_username = request.form["forum_username"]
# Get profile
profile = parser.get_profile("https://example.com", forum_username)
if not profile:
flash("Unable to find your forum user.", "error")
return redirect(url_for("link_forum_page", user=forum_username))
# Get stored key
stored_key = cache.get("forum_claim_key_" + request.remote_addr)
if not stored_key:
flash("Failed to get key", "error")
return redirect(url_for("link_forum_page", user=forum_username))
# Get token in signature
if not stored_key in profile.signature.text:
flash("Could not find the key in your signature!", "error")
return redirect(url_for("link_forum_page", user=forum_username))
# Get user from database
user = User.query.filter_by(username=current_user.username).first()
if not user:
flash("Could not find a user of that name!")
return redirect(url_for("link_forum_page", user=forum_username))
user.forum = forum_username
db.session.commit()
# SUCCESS! Redirect to index page
return redirect(url_for("index_page"))
# Register link_forum_page
@app.route("/user/claim/", methods=["POST", "GET"])
@login_required
def link_forum_page():
if request.method == "GET":
return link_forum_get()
else:
return link_forum_post()
Function split up to make it easier to read.
Signing in with a forum account #
The above is only good for linking, and not for actually signing in. To allow signing in, you could read public profile data off of the forum profile and then use OAuth to sign in with those.
For example, if the user has their Github listed on their forum profile, you can sign them in using that Github account.
- User gives forum username
- Server looks up Github field in forum username
- User signs in using Github to confirm identity
- Server redirects user to github authentication.
- Github redirects user to github callback with access token.
- Server looks up Github username using access token.
- Access token added to user model and accounts linked.
- If not logged in, server logs user into the account associated with that Github username.
Comments