How to Integrate App Authentication with an OCPP Central System

As EV charging infrastructure grows, user-friendly mobile apps and dashboards are essential. But how do you securely authenticate users in your app and link their actions to OCPP-connected chargers?

In this guide, we’ll show you how to build an app authentication system that works hand-in-hand with your OCPP central system (CSMS).


🧩 Architecture Overview

Components:

  • Mobile App / Dashboard – Where users sign in and control charging
  • Central System API (Flask) – REST API layer for users and admin actions
  • OCPP WebSocket Server – Communicates with EVSEs via OCPP 1.6
  • MongoDB – Stores users and charge point data

📊 Sequence Diagram: Start Charging via App

sequenceDiagram
    participant User as Mobile App
    participant API as Flask API Server
    participant CSMS as OCPP Central System
    participant EVSE as Charger (EVSE)

    User->>API: POST /api/login (username, password)
    API-->>User: JWT token + idTag

    User->>API: POST /api/start_charging (evse_id, connector_id, token)
    API->>CSMS: RemoteStartTransaction(idTag, connectorId)
    CSMS->>EVSE: RemoteStartTransaction.req
    EVSE-->>CSMS: RemoteStartTransaction.conf
    CSMS-->>API: status = Accepted
    API-->>User: {"status": "Accepted"}

This flow ensures only authenticated users can trigger OCPP commands like RemoteStartTransaction.


🔑 1. User Authentication via JWT

We use Flask-JWT-Extended to handle token-based auth.

Setup

Install:

pip install flask flask-jwt-extended pymongo werkzeug

Flask routes for signup and login:

@flask_app.route("/api/signup", methods=["POST"])
def signup():
    ...
    token = create_access_token(identity=user["username"])
    return jsonify(access_token=token, idTag=user["idTag"])

@flask_app.route("/api/login", methods=["POST"])
def login():
    ...
    token = create_access_token(identity=user["username"])
    return jsonify(access_token=token, idTag=user["idTag"])

⚡ 2. Secure OCPP Action (Remote Start)

@flask_app.route("/api/start_charging", methods=["POST"])
@jwt_required()
def start_charging():
    cp = connected_charge_points.get(evse_id)
    payload = call.RemoteStartTransactionPayload(id_tag=id_tag, connector_id=connector_id)
    future = asyncio.run_coroutine_threadsafe(cp.call(payload), main_loop)
    result = future.result(timeout=10)
    return jsonify({"status": result.status})

🧠 Best Practices

  • Hash passwords with werkzeug.security
  • Use JWTs and set expiration
  • Use idTag consistently across auth + OCPP
  • Restrict access by role (user/admin/root)
  • Link idTag to vehicles or accounts

🔧 Tools Used

Tool Purpose
Flask REST API backend
Flask-JWT Auth token generation
PyMongo MongoDB access
asyncio Concurrency + WebSocket calls
OCPP v1.6 Communication with EVSEs

🚀 Going Further

  • Add QR-based pairing: ocpp://CP001?connector=1
  • Add firmware update + diagnostics features
  • Build admin dashboard with user role control

Want the full source code or Postman test collection? Just ask!

Related Posts

Our Products


Related Posts

Our Products


Get in Touch with us

Speak to Us or Whatsapp(+66) 83001 0222

Chat with Us on LINEiiitum1984

Our HeadquartersChanthaburi, Thailand