X: A | Y: 1

Authflow

Authflow is an API-first identity and token service written in Go. It issues application-level JWTs, supports OAuth-based identity verification, and enforces secure logout using Redis-backed token revocation.

Designed for platforms that want a single JWT issuer for all downstream services, while keeping authentication methods flexible. Applications can integrate with Authflow using standard HTTP redirects and API calls — no client SDK is required.

What Authflow Is

Authflow acts as a centralized trust layer for modern applications and microservices.

AUTHORIZATION SERVICE — PRIMARY ROLE

  • Issues signed JWT access tokens (RS256)
  • Enforces token revocation using Redis
  • Acts as the single JWT authority for the system
  • Exposes a JWKS endpoint for downstream verification

AUTHENTICATION INTEGRATOR — SECONDARY ROLE

  • Supports OAuth 2.0 login for identity verification
  • Accepts upstream-authenticated identity via /mint
  • Keeps authentication method decoupled from token authority

DESIGN GOALS

Why Authflow

Most authentication products focus primarily on login UI, sessions, and frontend SDKs. Authflow is centered on a different responsibility:

No matter how a user authenticates, Authflow becomes the single service responsible for issuing, validating, and revoking application JWTs.

This gives downstream services a stable and simple trust model:

Key Architecture Principle

Authentication and token authority are intentionally separated.

This lets applications evolve their login methods without changing downstream authorization logic.

01

Centralized JWT Issuance

Single /mint endpoint issues signed JWT access tokens. One authority for your entire system.

02

RS256 Signing

Asymmetric signing with public key distribution via JWKS (/.well-known/jwks.json).

03

OAuth 2.0 Login Support

Use Authflow as the OAuth entry point for browser-based login.

04

Redis-backed Revocation

Immediate logout via Redis. Stores revoked:<jti> with TTL matching token expiry.

05

Stateless Verification

Downstream services verify JWT signatures locally. No auth server call per request.

06

Multi-client Registration

Register multiple clients with strict redirect URI validation.

07

SDK-less Integration

API-first model. Integrates directly using standard HTTP endpoints (no heavy client library).

08

Microservice-friendly

Clean provider-agnostic design. Keeps your application roles independent from the identity provider.

SDK-less Integration Model

Authflow does not require platform-specific SDKs. Applications integrate directly with Authflow using:

This makes Authflow usable from React, MERN, Django, Spring Boot, FastAPI, mobile apps, and other HTTP-capable clients without framework lock-in.

Supported Flows

Authflow supports two broad integration patterns.

1. OAUTH LOGIN FLOW

Use Authflow as the OAuth entry point for browser-based login. Useful for browser apps that want Authflow to handle OAuth and return an application token.

  1. Client redirects to GET /auth/{provider}
  2. OAuth provider authenticates the user
  3. Authflow validates the callback
  4. Authflow issues an application JWT
  5. Authflow redirects user to registered redirect_uri

2. TOKEN ISSUANCE (AFTER AUTH)

Mint an application JWT after identity has already been verified by the calling platform. Delegates token authority to Authflow without yielding the login experience.

  1. Client platform authenticates user using its own method
  2. Platform calls POST /mint
  3. Authflow issues an application JWT
  4. Downstream services trust only the Authflow-issued token

Issuance & Revocation

Token Issuance (/mint)

POST /mint issues an Authflow JWT for an already-authenticated user. Important: This is a token issuance endpoint, not an authentication endpoint. It assumes the caller has already verified the user's identity using a trusted flow.

JWKS Endpoint

Downstream services verify Authflow-issued JWTs using the public key served atGET /.well-known/jwks.json. No shared secret is required. Each downstream service fetches the public key from Authflow and verifies JWT signatures locally.

Logout and Token Revocation

Authflow implements logout as JWT revocation, not just browser session destruction.

  1. Client calls POST /logout with a Bearer token
  2. Authflow validates the JWT and extracts the jti claim
  3. Authflow stores revoked:{jti} in Redis
  4. The Redis entry expires automatically when the token would normally expire

JWT Claims

CLAIMDESCRIPTION
subSubject (user identifier)
issIssuer (authflow-go)
jtiUnique token ID
iatIssued at
expExpiration time
emailUser email
providerAuthentication source (google, local, sso)

Authentication & Authorization Model

Authflow focuses on token trust, not application-specific permission logic. Authflow answers:

The client platform still owns business authorization decisions (e.g., Is this user an admin? Can this user access tenant A?). This separation keeps application roles independent from the identity provider.

Two Integration Roles

A single service can be both a client and a downstream service.

ROLEWHAT YOU DO
ClientAuthenticate your user, then call /mint to get an Authflow JWT
Downstream serviceAccept Authflow JWTs on protected routes and verify them via JWKS

Step 0 — Register Your Application

Before calling /mint, register your app with Authflow to get a client_id and client_secret.

curl -X POST https://authflow-go.onrender.com/clients \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-app",
    "redirect_uri": "https://my-app.com/callback"
  }'

Response — save these, the secret is shown only once:

{
  "client_id": "550e8400-e29b-41d4-a716-446655440000",
  "client_secret": "7f3d9a1b-...",
  "redirect_uri": "https://my-app.com/callback"
}

Store AUTHFLOW_CLIENT_ID and AUTHFLOW_CLIENT_SECRET as environment variables. Never hardcode them.

How /mint Works

/mint is a token issuance endpoint, not an authentication endpoint. It assumes your service has already verified the user's identity. You are responsible for authentication — Authflow is responsible for the token.

Your service         Authflow
    |                    |
    |-- verify user ---→ |  (your logic: check password, OAuth, SSO)
    |                    |
    |-- POST /mint ----→ |  (with client_id + client_secret + sub)
    |                    |
    |←-- JWT ----------- |
    |                    |
    |-- return JWT --→ client

How JWT Verification Works

Downstream services verify Authflow JWTs using the public key served at:

GET https://authflow-go.onrender.com/.well-known/jwks.json

No shared secret is needed. Each service fetches the public key and verifies signatures locally — no call to Authflow per request.

Important: Cache the public key with a TTL (e.g. 1 hour) and retry the JWKS fetch on verification failure. This handles key rotation without breaking your service.

API Reference

METHODENDPOINTDESCRIPTION
GET/auth/{provider}Initiate OAuth flow. Redirects to provider authorization endpoint (e.g., Google).
GET/auth/{provider}/callbackOAuth callback. Validates authorization code & state, exchanges for credentials, issues JWT.
POST/mintIssue a JWT. Accepts sub, provider, and optional email. Does not authenticate — assumes identity is already verified.
POST/logoutRevoke a JWT. Validates token, extracts jti, writes revoked:<jti> to Redis with TTL.
GET/.well-known/jwks.jsonPublic key distribution for downstream JWT verification. No secret is shared.

Core JWT Flows

Mint Token
Logout / Revoke
OAuth Flow
Middleware (Go)
# Issue a JWT after authentication
POST /mint
Content-Type: application/json

{
  "sub": "username",
  "provider": "google | local | sso",
  "email": "user@example.com"
}

# Response
{
  "access_token": "eyJhbGciOiJIUzI1NiIs..."
}

# ⚠️ /mint does not authenticate users
# It assumes the caller has already verified identity

Plugging Into Your Service

Downstream services only need two things: The Authflow issuer (`authflow-go`) and the Authflow JWKS URL. No shared secret is required.

Python (Flask)
Python (FastAPI)
Node.js (Express)
Java (Spring Boot)
Go (chi)
import os
import time
import requests
from flask import Flask, request, jsonify
from flask_jwt_extended import JWTManager, jwt_required, get_jwt_identity
from jwt.algorithms import RSAAlgorithm

app = Flask(__name__)

# Flask session secret — not the JWT key
app.config["SECRET_KEY"] = os.environ["FLASK_SECRET_KEY"]

# Tell flask-jwt-extended to use RS256 and Authflow's public key
app.config["JWT_ALGORITHM"] = "RS256"
app.config["JWT_PUBLIC_KEY"] = _get_public_key()

jwt = JWTManager(app)

# --- JWKS with TTL cache ---
_jwks_cache = {"key": None, "fetched_at": 0}
JWKS_URL = "https://authflow-go.onrender.com/.well-known/jwks.json"
JWKS_TTL = 3600  # 1 hour

def _get_public_key():
    now = time.time()
    if _jwks_cache["key"] and (now - _jwks_cache["fetched_at"]) < JWKS_TTL:
        return _jwks_cache["key"]
    jwks = requests.get(JWKS_URL).json()
    key = RSAAlgorithm.from_jwk(jwks["keys"][0])
    _jwks_cache.update({"key": key, "fetched_at": now})
    return key

# --- Login: authenticate, then mint ---
@app.route("/login", methods=["POST"])
def login():
    data = request.json
    username = data.get("username")
    password = data.get("password")

    if not username or not password:
        return jsonify({"error": "Missing credentials"}), 400

    user = User.query.filter_by(username=username).first()
    if not user or not user.check_password(password):
        return jsonify({"error": "Invalid credentials"}), 401

    resp = requests.post(
        "https://authflow-go.onrender.com/mint",
        json={
            "sub": username,
            "provider": "local",
            "client_id": os.environ["AUTHFLOW_CLIENT_ID"],
            "client_secret": os.environ["AUTHFLOW_CLIENT_SECRET"],
        }
    )
    if resp.status_code != 200:
        return jsonify({"error": "Auth service unavailable"}), 500

    return resp.json(), 200

# --- Protected route ---
@app.route("/upload", methods=["POST"])
@jwt_required()
def upload():
    current_user = get_jwt_identity()  # returns sub claim
    # your logic here
    return jsonify({"user": current_user})

Environment Variables

VARIABLEUSED BYDESCRIPTION
AUTHFLOW_CLIENT_IDClient servicesIssued by POST /clients
AUTHFLOW_CLIENT_SECRETClient servicesIssued by POST /clients, shown once
AUTHFLOW_ISSUERDownstream servicesAlways authflow-go
AUTHFLOW_JWKS_URLDownstream serviceshttps://authflow-go.onrender.com/.well-known/jwks.json

Security Model

PROPERTYSTATUS
Single JWT issuerAuthflow only
Asymmetric signing (RS256)Private key never leaves Authflow
Public key distributionVia JWKS
Immediate logoutRedis-backed revocation
Stateless downstream validationNo auth server call per request
Downstream services mint tokensNever
Shared secret across servicesNot required

Good Fit For

Live Integration

Authflow is currently used in production as the authentication and token layer for:

rag-works.vercel.app →

You can test the full flow by creating an account with Google OAuth or username/password, logging in, accessing protected routes, and logging out.

© 2026 AUTHFLOW OPEN SOURCE
MAINTAINED BY @ABHIRAM-KARANTH