Integration guide

Add sign-in to your app, one chapter at a time

Follow one visitor from the moment they land on your sign-in page to the moment they're inside your app. Each chapter tells you what happens, what you build, and which API is involved.

About 10 minutes 1 element + 1 script 1 server-side API call

How a sign-in travels

Four parties take part: your visitor, your page, Aathorize, and your server. Here is the whole trip — pick a stop to jump to its chapter.

  1. 01

    Your page shows the widget

    A sign-in card with your logo appears.

    You add it once
  2. 02

    Your visitor signs in

    Google, an email code, WhatsApp…

    Shield handles it
  3. 03

    They come back to you

    With an access_token in the URL.

    Automatic redirect
  4. 04

    Your server asks who it is

    GET /api/auth/user

    Your one API call
  5. 05

    You open the door

    Start a session, show your app.

    Your code

Only chapter 4 is an API call you make yourself. The widget makes every other call for you.

Prologue

Set the scene in the dashboard

Before any code, tell Aathorize four things about your app. It takes about two minutes.

Create a project

Its name and logo are what your visitors see on the sign-in card.

New project

Choose sign-in methods

Google, Facebook, LinkedIn, email code or WhatsApp. Only active methods appear on the card.

Providers

Create an API key

You get a public key (pk_…) for the browser and a secret for your server. The secret is shown once — store it as AATHORIZE_API_SECRET.

API keys

Allow your callback URL

Add the origin of your redirect_uri, e.g. https://yourapp.com. An empty list allows any URL — lock it before launch.

URLs
Make every snippet yours

Change these and every code sample below updates as you type. Nothing is saved or sent anywhere.

From API keys. Safe to ship to the browser.

Where visitors land after signing in. A route on your server.

1

Chapter 1 · The welcome mat

Put the sign-in widget on your page

Your visitor clicks Sign in and lands on your login page. Instead of a form you have to build, secure and maintain, they're greeted by a sign-in card with your logo on it. That card is <shield-auth> — a standard web component, so it works with every framework, or none at all.

Your move: add the <shield-auth> element where the card should appear, and load the script once. The script URL already carries your public key, so there is nothing else to configure.

No build step, no framework. Paste this into the page where people sign in.

login.html HTML
<!doctype html>
<html lang="en">
  <body>
    <main class="sign-in">
      <!-- 1. The stage: Shield draws the sign-in card here -->
      <shield-auth
        theme="light"
        redirect_uri="https://yourapp.com/auth/callback"
      ></shield-auth>
    </main>

    <!-- 2. The actor: the widget, already bound to your public key -->
    <script src="https://aathorize.com/embed/shield/YOUR_PUBLIC_KEY.js" async></script>
  </body>
</html>
Attribute Value What it does
theme light · dark Colours of the card. Defaults to light.
redirect_uri Required · full URL Where the visitor goes after signing in. Its origin must be on your URLs list.
api_url Optional Points the widget at another API, such as a local backend. Leave it out in production.
Checkpoint: reload the page. You should see your logo and one button per sign-in method. If the space stays empty, jump to Troubleshooting.
2

Chapter 2 · Proving who they are

Your visitor picks a way in

Maybe they tap Continue with Google. Maybe they'd rather get a code by email, or scan a WhatsApp QR code with their phone. Whichever they choose, Shield runs the whole conversation — the OAuth redirects, sending and checking codes, waiting for the WhatsApp message — and records the sign-in in your analytics.

Your move: nothing. There is no code in this chapter. It is here so you know what you're looking at when you open the Network tab.
Method What the widget calls
Google, Facebook, LinkedIn
GET /api/auth/social/{signature}/{provider}

Then the provider's consent screen, then back through Aathorize.

Email code
POST /api/auth/{signature}/email
POST /api/auth/{signature}/email/verify

The first sends a 5-digit code; the second checks what the visitor typed.

WhatsApp
GET /api/auth/{signature}/whatsapp
GET /api/auth/{signature}/whatsapp/verify

The first shows a QR code; the widget polls the second every second until the message arrives.

Checkpoint: sign in once with a method you enabled. You will need a real sign-in for the next chapter.
3

Chapter 3 · The trip home

Shield sends them back to your callback

Signed in, your visitor is sent back to the redirect_uri you chose. Two query parameters ride along: whether it worked, and an access token that stands for this person.

The visitor's address bar
https://yourapp.com/auth/callback?success=true&access_token=oat_MTI.cWx2ZnN0dXZ3eHl6YWJjZGVmZ2g
If they cancel or the provider refuses
https://yourapp.com/auth/callback?success=false
Parameter Meaning
success true or false. false means the visitor cancelled or the provider refused.
access_token Only present when success=true. A bearer token (it starts with oat_) that Aathorize can resolve to this visitor.
Don't trust the URL on its own: anyone can type ?success=true into an address bar. The token only means something once your server has checked it with Aathorize — that's the next chapter.
Your move: create the route that lives at your redirect_uri (/auth/callback). It reads both parameters and, when success isn't true, sends the visitor back to sign in with a friendly message. The server examples in chapter 4 include this.
4

Chapter 4 · The question

Your server asks Aathorize: who is this?

Your server is holding a token and needs a name to put to it. So it asks Aathorize the only question this integration requires — who does this token belong to? — and proves it's really you by sending your API secret alongside.

The one call you make GET https://api.aathorize.com/v1/api/auth/user
Header Value Where it comes from
Authorization Bearer <access_token> The callback URL, chapter 3
x-api-secret <your API secret> API keys, shown once when you create a key
Server only: this request carries your secret. Make it from your backend, a serverless function or an edge worker — never from browser JavaScript, where anyone can read it. No backend yet? A single Cloudflare Worker or Vercel function is enough.

An Express route at your redirect_uri. Node 18+ ships fetch, so there is nothing extra to install for the API call.

server.js JavaScript
// npm i express express-session
import express from "express";
import session from "express-session";

const app = express();
app.use(session({ secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false }));

// The redirect_uri you gave the widget points here.
app.get("/auth/callback", async (req, res) => {
  const { success, access_token } = req.query;
  if (success !== "true" || !access_token) {
    return res.redirect("/login?error=cancelled");
  }

  // Ask Aathorize who this is. The secret never leaves your server.
  const response = await fetch("https://api.aathorize.com/v1/api/auth/user", {
    headers: {
      Authorization: `Bearer ${access_token}`,
      "x-api-secret": process.env.AATHORIZE_API_SECRET,
    },
  });
  const data = await response.json();
  if (!data.success) {
    return res.redirect("/login?error=unauthorized");
  }

  // data.user → { id, name, identities: [{ type, value }] }
  req.session.regenerate((err) => {
    if (err) return res.redirect("/login?error=session");
    req.session.user = data.user;
    res.redirect("/dashboard"); // a clean URL: the token leaves the address bar
  });
});

app.listen(3000);

What comes back

200 OK
{
  "success": true,
  "message": "User details retrieved successfully",
  "user": {
    "id": "user_cm1x8q0z70001wxyz5678ijkl",
    "name": "Asha Rao",
    "identities": [
      { "type": "email", "value": "asha@example.com" }
    ]
  }
}
When something is off
// 401 — the access token is missing, malformed or unknown
{ "success": false, "error": "Unauthorized Access" }

// 200 — the token is fine but the API secret is wrong or revoked
{ "success": false, "message": "Unauthorized access" }

Always check success in the body — a wrong secret still answers with HTTP 200.

Checkpoint: log data.user once and sign in as yourself. You should see your own name and email.
5

Chapter 5 · Opening the door

Give your visitor a session

Aathorize has vouched for your visitor. Everything from here belongs to your app: find or create their account, start a session, and send them somewhere useful — on a clean URL, so the token leaves the address bar for good.

Field What it holds
user.id Stable for this person in this project, e.g. user_cm1x…. Link accounts on this.
user.name Display name from the provider, or the part of the email before the @.
user.identities A list of { type, value }, where type is email or phone. Email and social sign-ins bring an email; WhatsApp brings a phone number.
lib/accounts.ts TypeScript
type AathorizeUser = {
  id: string;
  name: string;
  identities: { type: "email" | "phone"; value: string }[];
};

export async function findOrCreateAccount(user: AathorizeUser) {
  const email = user.identities.find((i) => i.type === "email")?.value ?? null;
  const phone = user.identities.find((i) => i.type === "phone")?.value ?? null;

  // user.id is stable for this project — link on it, not on email.
  return db.account.upsert({
    where: { aathorizeId: user.id },
    create: { aathorizeId: user.id, name: user.name, email, phone },
    update: { name: user.name },
  });
}
  • Link on user.id, not on email — someone who signs in with WhatsApp may have no email at all.
  • Keep the session on your server: an HttpOnly cookie holding a random id, or a signed session.
  • Redirect after the exchange so the token doesn't linger in browser history, logs or Referer headers.

The end — and the beginning.

That's the whole story: one element, one script, one API call. Your visitor is in, and you never stored a password.

Go-live checklist

  • Your production origin is on the URLs list. Once the list has one entry, every other origin is rejected.
  • AATHORIZE_API_SECRET lives only in server environment variables — not in frontend code, not in git.
  • Your redirect_uri uses HTTPS.
  • Your callback handles success=false with a clear way back to sign in.
  • You redirect to a clean URL right after the exchange, so the token leaves the address bar.
  • Accounts are linked on user.id, not on email.
  • You signed in once with every enabled method, on the production domain.
  • To rotate keys: create a new key, deploy it, then revoke the old one.

API reference

Base URL: https://api.aathorize.com/v1. Only the last row is yours to call; the rest are listed for debugging.

Endpoint Called by Auth Purpose
GET https://aathorize.com/embed/shield/{public_key}.js Browser Public key in the URL Loads the widget
POST /api/details Widget x-api-key Branding, sign-in methods and a signature
GET /api/auth/social/{signature}/{provider} Widget Signature Starts Google, Facebook or LinkedIn
POST /api/auth/{signature}/email Widget Signature Emails a 5-digit code
POST /api/auth/{signature}/email/verify Widget Signature Checks the code, returns the redirect
GET /api/auth/{signature}/whatsapp Widget Signature Shows the WhatsApp QR code
GET /api/auth/{signature}/whatsapp/verify Widget Signature Polls until WhatsApp approves
GET /api/auth/user Your server Bearer token + x-api-secret Tells you who signed in

Troubleshooting