Docs/Authentication

Authentication

Astapa handles the entire authentication flow for your end users. Redirect them to our hosted login page, we handle signup, email verification, OAuth, and password resets. You get back a signed JWT with the user's identity and claims.

Supported sign-in methods

📧
Email & Password
With email verification
Google OAuth
One-click sign in
GitHub OAuth
For developer tools

1Get your credentials

Create a project in your dashboard. You'll need three things:

CredentialWhere to find it
client_idProject settings → General
client_secretProject settings → General (shown once)
redirect_uriProject settings → Redirect URIs
Keep your client_secret safe
Never expose your client_secret in client-side code. The token exchange must happen on your server.

2Redirect to hosted login

Send your users to Astapa's hosted login page. The URL takes two required query parameters: your client_id and the redirect_uri where we'll send them after authentication.

The hosted login page handles everything: signup, login, email verification, password reset, and OAuth. Your users never leave a polished, branded experience.

login.tstypescript
const loginUrl = "https://astapa.com/auth/login";
const params = new URLSearchParams({
  client_id: "your_client_id",
  redirect_uri: "https://yourapp.com/callback",
});

// Redirect the user
window.location.href = `${loginUrl}?${params}`;
Base URL
The examples use astapa.com. If you're self-hosting, replace with your deployment's origin.

3Exchange the authorization code

After the user authenticates, we redirect them to your redirect_uri with a code query parameter. Your backend exchanges this code for tokens:

callback.tstypescript
// In your callback route handler
const code = searchParams.get("code");

const res = await fetch("https://astapa.com/api/platform/token", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    grant_type: "authorization_code",
    code,
    client_id: process.env.ASTAPA_CLIENT_ID,
    client_secret: process.env.ASTAPA_CLIENT_SECRET,
    redirect_uri: "https://yourapp.com/callback",
  }),
});

const { access_token, refresh_token, token_type, expires_in } = await res.json();

// Store tokens securely (httpOnly cookies recommended)
// access_token expires in 3600 seconds (1 hour)
// refresh_token is long-lived — use it to get new access tokens

4Verify the JWT

The access token is a signed JWT (RS256). Verify it using our JWKS endpoint to get the public key. This ensures the token hasn't been tampered with and was issued by Astapa.

middleware.tstypescript
import jwt from "jsonwebtoken";
import jwksClient from "jwks-rsa";

const client = jwksClient({
  jwksUri: "https://astapa.com/.well-known/jwks.json",
  cache: true,
  rateLimit: true,
});

function getKey(header, callback) {
  client.getSigningKey(header.kid, (err, key) => {
    callback(err, key?.getPublicKey());
  });
}

// Verify the token
jwt.verify(access_token, getKey, { algorithms: ["RS256"] }, (err, decoded) => {
  // decoded.sub        → end user ID
  // decoded.email      → user email
  // decoded.custom_claims.plan → subscription plan
});
Cache the JWKS
The JWKS endpoint returns public keys that rarely change. Use a caching client (like jwks-rsa) to avoid hitting the endpoint on every request.

Refreshing tokens

Access tokens expire after 1 hour. Use the refresh token to get a new access token without asking the user to log in again. This is typically done in your middleware when you detect an expired JWT.

refresh.tstypescript
const res = await fetch("https://astapa.com/api/platform/token", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    grant_type: "refresh_token",
    refresh_token: stored_refresh_token,
    client_id: process.env.ASTAPA_CLIENT_ID,
    client_secret: process.env.ASTAPA_CLIENT_SECRET,
  }),
});

const { access_token, refresh_token } = await res.json();
// Both tokens are rotated — store the new refresh_token
Refresh token rotation
Each refresh returns a new refresh token. The old one is invalidated. Always store the latest refresh token.

Revoking tokens (logout)

To log a user out completely, revoke their refresh tokens server-side, then clear any cookies or local storage on the client. The user won't be able to refresh their session anymore.

logout.tstypescript
// Revoke all refresh tokens for this user
await fetch("https://astapa.com/api/platform/revoke", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    client_id: process.env.ASTAPA_CLIENT_ID,
    client_secret: process.env.ASTAPA_CLIENT_SECRET,
    email: "user@example.com", // or end_user_id: 42
  }),
});

// Then clear cookies on the client side

API reference

Complete endpoint documentation for the authentication flow.

Next steps

API Playground
Click "Try it" on any endpoint to get started.
Authentication | Astapa