Python / Flask
Implement Epilogue Auth with Python and Flask
Installation
pip install flask requests python-dotenv sqlalchemyEnvironment Variables
Create a .env file:
AUTH_URL=https://auth.epilogue.team/authorize/your-app-id
APP_ID=your-app-id
APP_SECRET=your-app-secret
DATABASE_URL=sqlite:///app.dbModels
# models.py
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
import uuid
db = SQLAlchemy()
class User(db.Model):
id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
auth_user_id = db.Column(db.String(255), unique=True, nullable=False)
name = db.Column(db.String(255), nullable=False)
profile_image = db.Column(db.String(500), nullable=True)
sessions = db.relationship('Session', backref='user', lazy=True)
class Session(db.Model):
id = db.Column(db.String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
token = db.Column(db.String(255), unique=True, nullable=False)
user_id = db.Column(db.String(36), db.ForeignKey('user.id'), nullable=False)
expires_at = db.Column(db.DateTime, nullable=False)Auth Routes
# routes/auth.py
import os
import secrets
import string
import requests
from datetime import datetime, timedelta
from flask import Blueprint, redirect, request, jsonify
auth_bp = Blueprint('auth', __name__, url_prefix='/api/auth')
def generate_random_string(length=200):
alphabet = string.ascii_letters + string.digits
return ''.join(secrets.choice(alphabet) for _ in range(length))
@auth_bp.route('/start')
def start():
"""Redirect to Epilogue Auth"""
return redirect(os.environ['AUTH_URL'])
@auth_bp.route('/callback')
def callback():
"""Handle callback from Epilogue Auth"""
from models import db, User, Session
code = request.args.get('code')
if not code:
return jsonify({'error': 'Missing code'}), 400
try:
# Exchange code for token
token_response = requests.post(
f"https://auth.epilogue.team/api/v1/authorize/{os.environ['APP_ID']}",
json={
'authorizationCode': code,
'applicationSecret': os.environ['APP_SECRET']
},
headers={'Content-Type': 'application/json'}
)
token_data = token_response.json()
token = token_data['token']
# Fetch user info
user_response = requests.get(
'https://auth.epilogue.team/api/v1/app/me',
headers={
'Content-Type': 'application/json',
'Authorization': f'Bearer {token}'
}
)
user_data = user_response.json()
if 'error' in user_data:
raise Exception(user_data['error'])
# Find or create user
user = User.query.filter_by(auth_user_id=user_data['id']).first()
if not user:
user = User(
auth_user_id=user_data['id'],
name=user_data.get('username') or f"user_{user_data['id']}",
profile_image=user_data.get('iconUrl')
)
db.session.add(user)
db.session.commit()
# Create session
session_token = generate_random_string(200)
session = Session(
token=session_token,
user_id=user.id,
expires_at=datetime.utcnow() + timedelta(days=1)
)
db.session.add(session)
db.session.commit()
# Return token to client
return f'''
<html><body><script>
localStorage.setItem("token", "{session_token}");
window.location.href = "/";
</script></body></html>
'''
except Exception as e:
print(f"Error: {e}")
return jsonify({'error': 'Internal server error'}), 500
@auth_bp.route('/me')
def me():
"""Get current user info"""
from models import Session
auth_header = request.headers.get('Authorization', '')
token = auth_header.replace('Bearer ', '') or request.args.get('token')
if not token:
return jsonify({'error': 'Authentication required'}), 401
session = Session.query.filter(
Session.token == token,
Session.expires_at > datetime.utcnow()
).first()
if not session:
return jsonify({'error': 'Invalid or expired token'}), 401
return jsonify({
'id': session.user.id,
'name': session.user.name,
'profileImage': session.user.profile_image
})Main App
# app.py
import os
from dotenv import load_dotenv
from flask import Flask
load_dotenv()
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', 'sqlite:///app.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
from models import db
db.init_app(app)
from routes.auth import auth_bp
app.register_blueprint(auth_bp)
with app.app_context():
db.create_all()
if __name__ == '__main__':
app.run(debug=True, port=3000)Running the App
python app.pyVisit http://localhost:3000/api/auth/start to begin authentication.