casdoor-qr-auth
v1.0.1
Published
Drop-in Express middleware for Casdoor QR code authentication
Maintainers
Readme
casdoor-qr-auth
Drop-in Express middleware that adds full Casdoor QR code authentication to any Node.js app in one app.use() call.
How it works
Desktop browser Phone
────────────────── ───────────────────────────
GET /login (scans QR)
← QR page rendered → GET /_qr/auth?sid=...
polls /_qr/status → Casdoor OAuth (authorize)
← GET /auth/callback?code=&state=sid
token exchanged, session confirmed
status = "confirmed"
POST /_qr/finalize ← "Login Confirmed" page on phone
user written to session
redirect → /profileInstall
npm install casdoor-qr-authPeer dependency: express (v4 or v5)
Usage
require('dotenv').config();
const express = require('express');
const session = require('express-session');
const casdoorQRAuth = require('casdoor-qr-auth');
const fs = require('fs');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// express-session MUST be configured before casdoor-qr-auth
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
}));
// Mount the auth middleware — that's it!
app.use(casdoorQRAuth({
endpoint: process.env.CASDOOR_ENDPOINT,
clientId: process.env.CASDOOR_CLIENT_ID,
clientSecret: process.env.CASDOOR_CLIENT_SECRET,
certificate: fs.readFileSync('./certificate.pem', 'utf8'),
orgName: process.env.CASDOOR_ORG_NAME,
appName: process.env.CASDOOR_APP_NAME,
baseUrl: process.env.BASE_URL, // public URL of your app
}));
// Your own routes — req.session.user is populated after login
app.get('/profile', (req, res) => {
if (!req.session.user) return res.redirect('/login');
res.send(`Hello, ${req.session.user.displayName}!`);
});Options
| Option | Type | Required | Default | Description |
|------------------|------------|----------|--------------------|-------------|
| endpoint | string | ✅ | — | Casdoor server URL |
| clientId | string | ✅ | — | OAuth client ID |
| clientSecret | string | ✅ | — | OAuth client secret |
| certificate | string | ✅ | — | Casdoor public cert (PEM string) |
| orgName | string | ✅ | — | Casdoor org name |
| appName | string | ✅ | — | Casdoor app name |
| baseUrl | string | ✅ | — | Public URL of your app |
| loginPath | string | — | '/login' | Path for the QR login page |
| callbackPath | string | — | '/auth/callback' | OAuth redirect_uri path — must match Casdoor config |
| qrTtlMs | number | — | 300000 (5 min) | QR code expiry in milliseconds |
| sessionUserKey | string | — | 'user' | Key used on req.session to store the user |
| onLogin | function | — | redirect to '/' | async (req, res, user) => void — called after successful login |
| onError | function | — | 500 response | async (req, res, err) => void — called on OAuth errors |
Routes mounted by the middleware
| Method | Path | Description |
|--------|-------------------|-------------|
| GET | /login | Serves the QR login page (configurable via loginPath) |
| GET | /auth/callback | OAuth redirect_uri — exchanges code for token (configurable via callbackPath) |
| GET | /_qr/auth | Phone lands here after scanning QR |
| GET | /_qr/status | Desktop polls for session status |
| POST | /_qr/finalize | Desktop calls to write user to session |
| GET | /_qr/logout | Destroys session and redirects to loginPath |
After login
The authenticated user object is available at req.session.user (or whatever key you set via sessionUserKey). The object is the parsed Casdoor JWT payload and includes:
{
name: 'jsmith',
displayName: 'John Smith',
email: '[email protected]',
phone: '+1...',
owner: 'my-org',
avatar: 'https://...',
id: 'uuid...',
// ...all other Casdoor JWT claims
}Environment variables (example .env)
CASDOOR_ENDPOINT=https://sso.example.com
CASDOOR_CLIENT_ID=your-client-id
CASDOOR_CLIENT_SECRET=your-client-secret
CASDOOR_ORG_NAME=your-org
CASDOOR_APP_NAME=your-app
BASE_URL=https://app.example.com
SESSION_SECRET=a-long-random-string
PORT=3000Casdoor setup checklist
- In your Casdoor app settings, add
{BASE_URL}/auth/callbackto Redirect URIs - Download the app's certificate and save it as
certificate.pemalongside your app - Set Grant types to include
authorization_code
License
MIT
