Integration kit

Integration kit

Drop-in code for web, mobile and server integrations with Evantra Identity.

Installation

Add Evantra Identity to your app

Use the React package for web and mobile apps. Use the SDK for servers, desktop apps and CLI tools.

Web · React / Next · React Native
pnpm add @evantra-identity/react
Server · Desktop · CLI
pnpm add @evantra-identity/sdk

Web · start the flow

Authorization code with PKCE

Start authorizationts
import {
  createEvantraAuthorizeUrl,
  createEvantraPkcePair,
  createEvantraState,
} from "@evantra-identity/react";

// The authorize endpoint lives on the identity API host.
const API = "https://evantra-headquarters.onrender.com";
const REDIRECT_URI = "https://app.example.com/oauth/callback";

// 1. Create the PKCE verifier and a CSRF state value
const { verifier, challenge } = await createEvantraPkcePair();
const state = createEvantraState();

sessionStorage.setItem("evantra_pkce_verifier", verifier);
sessionStorage.setItem("evantra_oauth_state", state);

// 2. Send the user to the authorization endpoint
window.location.assign(
  createEvantraAuthorizeUrl(API, {
    clientId: "evt_client_...",
    redirectUri: REDIRECT_URI,
    codeChallenge: challenge,
    codeChallengeMethod: "S256",
    scope: "openid profile email",
    state,
  }),
);

Web · handle the callback

Exchange the code on your callback route

Callback routetsx
// app/oauth/callback/page.tsx
"use client";

import { useEffect } from "react";
import {
  consumeEvantraWebCallback,
  exchangeEvantraCode,
} from "@evantra-identity/react";

const REDIRECT_URI = "https://app.example.com/oauth/callback";

export default function Callback() {
  useEffect(() => {
    async function complete() {
      // Reads ?code= and strips it from the address bar
      const { code } = consumeEvantraWebCallback(
        sessionStorage.getItem("evantra_oauth_state"),
      );

      const tokens = await exchangeEvantraCode(
        { clientId: "evt_client_..." },
        {
          code,
          codeVerifier:
            sessionStorage.getItem("evantra_pkce_verifier") ?? "",
          redirectUri: REDIRECT_URI,
        },
      );

      // Hand the token to YOUR backend to start your own session
      await fetch("/api/session", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ accessToken: tokens.access_token }),
      });

      window.location.assign("/dashboard");
    }

    void complete();
  }, []);

  return <p>Completing sign in...</p>;
}

Mobile · React Native / Expo

Deep-link redirect with secure verifier storage

Register a reverse-DNS scheme such as com.example.app://oauth/callback against your client before using this flow.

Mobile authorizationts
import * as WebBrowser from "expo-web-browser";
import * as SecureStore from "expo-secure-store";
import {
  createEvantraAuthorizeUrl,
  createEvantraPkcePair,
  createEvantraState,
  consumeEvantraNativeCallback,
  exchangeEvantraCode,
} from "@evantra-identity/react";

const API = "https://evantra-headquarters.onrender.com";
const REDIRECT_URI = "com.example.app://oauth/callback";
const CLIENT_ID = "evt_client_...";

// 1. PKCE + state, held in the OS keychain/keystore
const { verifier, challenge } = await createEvantraPkcePair();
const state = createEvantraState();

await SecureStore.setItemAsync("evantra_pkce_verifier", verifier);
await SecureStore.setItemAsync("evantra_oauth_state", state);

// 2. Open the system browser
const result = await WebBrowser.openAuthSessionAsync(
  createEvantraAuthorizeUrl(API, {
    clientId: CLIENT_ID,
    redirectUri: REDIRECT_URI,
    codeChallenge: challenge,
    state,
  }),
  REDIRECT_URI,
);

if (result.type !== "success" || !result.url) {
  throw new Error("Sign in was cancelled.");
}

// 3. Read the code from the deep link
const { code } = consumeEvantraNativeCallback(result.url, state);

const tokens = await exchangeEvantraCode(
  { clientId: CLIENT_ID },
  {
    code,
    codeVerifier:
      (await SecureStore.getItemAsync("evantra_pkce_verifier")) ?? "",
    redirectUri: REDIRECT_URI,
  },
);

Server / desktop / CLI

The SDK handles exchange and profile loading

SDK clientts
import { EvantraOAuthClient, parseEvantraCallback } from "@evantra-identity/sdk";

const client = new EvantraOAuthClient({
  clientId: "evt_client_...",
  redirectUri: "https://api.example.com/oauth/callback",
  scope: "openid profile email",
  // clientSecret: "..."  // confidential clients only
});

// On your callback route
const { code } = parseEvantraCallback(requestUrl, savedState);

// Exchange AND load the profile in one call
const { tokens, profile } = await client.completeAuthorization({
  code,
  codeVerifier: savedVerifier,
});

console.log("Signed in as", profile.evantra_id);

Optional · hosted sign-in buttons

Link straight to the hosted pages

These buttons point at the hosted sign-in and registration pages. Use them for a simple integration, or use the OAuth flow above when you need your own token exchange.

React componentstsx
import {
  EvantraIdentityProvider,
  EvantraSignInButton,
  EvantraRegisterButton,
} from "@evantra-identity/react";

// returnTo is a same-origin path on the identity app,
// so the identity service can never be used as an
// open redirect.
export function LoginSection() {
  return (
    <EvantraIdentityProvider
      config={{
        identityWebBaseUrl: "https://identity.evantradebuckman.com",
        identityApiBaseUrl: "https://evantra-headquarters.onrender.com",
        clientId: "evt_client_...",
      }}
    >
      <EvantraSignInButton returnTo="/welcome">
        Sign in with Evantra
      </EvantraSignInButton>

      <EvantraRegisterButton returnTo="/welcome">
        Create account
      </EvantraRegisterButton>
    </EvantraIdentityProvider>
  );
}

Endpoints

Identity API surface

GET/oauth/authorize

Starts the flow and, once consent is given, redirects back to your redirect_uri with a code.

POST/oauth/token

Exchanges an authorization code or refresh token for tokens.

GET/oauth/userinfo

Returns the OpenID Connect profile for a Bearer access token.

POST/oauth/revoke

Revokes an access or refresh token.

POST/oauth/introspect

Reports whether a token is active and what it may access.

Base URL: https://evantra-headquarters.onrender.com

Integration checklist

  • Register the OAuth client and its exact redirect URIs first.
  • Use PKCE with S256 on every authorization request.
  • Send state and verify it when the code returns.
  • Keep client secrets server-side only — never in a browser or app binary.
  • Exchange the single-use code promptly, and refresh tokens as needed.
  • Check email_verified before trusting a contact address.
  • Keep app-level authorization and role checks in your product.

Protected by Evantra Identity