Civic Docs
Civic Auth
Civic Auth
  • 🔏Civic Auth
  • Integration
    • React
    • Next.JS
    • Node.JS
      • Express
      • Hono
      • Fastify
    • Other OIDC / OAuth 2.0-Compliant Environments
    • FAQs
    • Error Codes
    • Bring Your App to Production
  • Web3
    • Embedded Wallets
    • Ethereum / EVM
    • Solana
Powered by GitBook
On this page
  • 1. Install dependencies
  • 2. Configure your App
  • 3. Set up Cookies
  • 4. Create a Login Endpoint
  • 5. Create a Logout Endpoint
  • 6. Create the Callback Endpoint
  • 7. Add Middleware
  • 8. Use the Session
  • PKCE and Client Secrets

Was this helpful?

  1. Integration
  2. Node.JS

Express

PreviousNode.JSNextHono

Last updated 2 months ago

Was this helpful?

Follow these simple steps to set up Civic Auth with an backend (a working example is available in our ).

1. Install dependencies

npm install @civic/auth cookies-parser
yarn add @civic/auth cookies-parser
pnpm install @civic/auth cookies-parser
bun add @civic/auth cookies-parser

2. Configure your App

Your app will need the following configuration:

const config = {
  clientId: // Client ID from auth.civic.com
  redirectUrl: 'http://localhost:3000/auth/callback' // change to your domain when deploying,
  postLogoutRedirectUrl: 'http://localhost:3000/' // The postLogoutRedirectUrl is the URL where the user will be redirected after successfully logging out from Civic's auth server.
};

Note: redirectUrl and postLogoutRedirectUrl must be absolute URLs.

3. Set up Cookies

Civic Auth uses cookies for storing the login state by default

import express, { Request, Response } from 'express';
import { CookieStorage, CivicAuth } from '@civic/auth/server';
import cookieParser from 'cookie-parser';

app.use(cookieParser());

// Tell Civic how to get cookies from your node server
class ExpressCookieStorage extends CookieStorage {
  constructor(private req: Request, private res: Response) {
    super({
      secure: false
    })
  }

  async get(key: string): Promise<string | null> {
    return Promise.resolve(this.req.cookies[key] ?? null);
  }

  async set(key: string, value: string): Promise<void> {
    await this.res.cookie(key, value, this.settings);
  }
}

app.use((req, res, next) => {
  // add an instance of the cookie storage and civicAuth api to each request
  req.storage = new ExpressCookieStorage(req, res);
  req.civicAuth = new CivicAuth(req.storage, config);
  next();
});

4. Create a Login Endpoint

This endpoint will handle login requests, build the Civic login URL and redirect the user to it.

import { buildLoginUrl } from '@civic/auth/server';

app.get('/', async (req: Request, res: Response) => {
  const url = await req.civicAuth.buildLoginUrl();

  res.redirect(url.toString());
});

5. Create a Logout Endpoint

This endpoint will handle logout requests, build the Civic logout URL and redirect the user to it.

import { buildLogoutRedirectUrl } from '@civic/auth/server';

app.get('/auth/logout', async (req: Request, res: Response) => {
  const url = await req.civicAuth.buildLogoutRedirectUrl();
  res.redirect(url.toString());
});

6. Create the Callback Endpoint

This endpoint handles successful logins and creates the session

import { resolveOAuthAccessCode } from '@civic/auth/server';

app.get('/auth/callback', async (req: Request, res: Response) => {
  const { code, state } = req.query as { code: string; state: string };

  await req.civicAuth.resolveOAuthAccessCode(code, state);
  res.redirect('/admin/hello');
});

7. Add Middleware

Middleware protects routes that require login.

import { isLoggedIn } from '@civic/auth/server';

const authMiddleware = async (req: Request, res: Response, next: NextFunction) => {
  if (!(await req.civicAuth.isLoggedIn())) return res.status(401).send('Unauthorized');
  next();
};

// Apply authentication middleware to any routes that need it
app.use('/admin', authMiddleware);

8. Use the Session

If needed, get the logged-in user information.

import { user } from '@civic/auth/server';

app.get('/admin/hello', async (req: Request, res: Response) => {
  const user = await req.civicAuth.getUser();
  res.send(`Hello, ${user?.name}!`);
});

PKCE and Client Secrets

When using the Civic Auth SDK, PKCE is handled entirely by the library.

Civic Auth uses , to protect users and clients from unauthorized access to user information. This, alongside domain registration for apps in production environments, mean that you don't need to provide a client secret in your backend.

Express
github examples repo
PKCE (Proof Key for Code Exchange)