npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@glideidentity/glide-fe-sdk-web

v2.2.0

Published

Glide Phone Authentication SDK for web applications

Downloads

57

Readme

Glide Web Client SDK

The official web SDK for integrating Glide's carrier-grade phone verification into your web applications.

Features

  • 🚀 Instant Verification - Direct carrier verification without SMS delays
  • 🔐 Fraud Resistant - Can't be intercepted or spoofed like SMS codes
  • 📱 Multi-Platform - Desktop QR codes, iOS App Clips, Android deep links
  • 🎨 Customizable UI - Built-in modal with themes and view modes
  • 🔧 Flexible Architecture - Use the full SDK or just the core types
  • 🌐 Framework Support - React, Vue, Angular, and vanilla JavaScript
  • 📦 Tree-Shakeable - Import only what you need

Installation

npm install @glideidentity/glide-fe-sdk-web

Quick Start

High-Level API (Recommended)

The simplest way to integrate phone verification:

import { PhoneAuthClient, USE_CASE } from '@glideidentity/glide-fe-sdk-web';

const client = new PhoneAuthClient({
  endpoints: {
    prepare: '/api/magical-auth/prepare',
    reportInvocation: '/api/magical-auth/report-invocation',
    process: '/api/magical-auth/process',
  }
});

// Get a phone number
const result = await client.authenticate({
  use_case: USE_CASE.GET_PHONE_NUMBER
});
console.log('Phone:', result.phone_number);

// Or verify a specific number
const verified = await client.authenticate({
  use_case: USE_CASE.VERIFY_PHONE_NUMBER,
  phone_number: '+14155551234'
});
console.log('Verified:', verified.verified);

Granular API

For more control over the authentication flow:

import { PhoneAuthClient, USE_CASE } from '@glideidentity/glide-fe-sdk-web';

const client = new PhoneAuthClient({
  endpoints: {
    prepare: '/api/magical-auth/prepare',
    reportInvocation: '/api/magical-auth/report-invocation',
    process: '/api/magical-auth/process',
  }
});

// Step 1: Prepare the request
const prepared = await client.prepare({
  use_case: USE_CASE.VERIFY_PHONE_NUMBER,
  phone_number: '+14155551234'
});

// Step 2: Invoke authentication (shows UI based on strategy)
const invokeResult = await client.invokeSecurePrompt(prepared);
const credential = await invokeResult.credential;

// Step 3: Process the credential
const result = await client.verifyPhoneNumber(credential, invokeResult.session);

console.log('Verified:', result.verified);

Configuration

Client Options

const client = new PhoneAuthClient({
  // Backend endpoints (with defaults shown)
  endpoints: {
    prepare: '/api/magical-auth/prepare',              // Prepare request endpoint
    process: '/api/magical-auth/process',              // Process credential endpoint
    reportInvocation: '/api/magical-auth/report-invocation', // ASR tracking endpoint
    polling: undefined,                              // Optional: Status polling endpoint
  },
  
  // Polling configuration
  pollingInterval: 2000,      // Polling interval in ms (default: 2000)
  maxPollingAttempts: 30,     // Max attempts before timeout (default: 30)
  timeout: 30000,             // API request timeout in ms (default: 30000)
  
  // Debug options
  debug: false,               // Enable console logging (default: false)
  devtools: {
    showMobileConsole: false  // Show on-screen console on mobile (default: false)
  },
  
  // Dev environment routing (e.g., 'dev7' adds 'developer' header)
  devEnv: undefined,
});

Invoke Options

Customize the authentication UI and behavior:

const result = await client.invokeSecurePrompt(prepared, {
  // Prevent SDK from showing any UI (use your own)
  preventDefaultUI: false,
  
  // Polling configuration (overrides client config)
  pollingInterval: 2000,
  maxPollingAttempts: 30,
  
  // Modal customization (for desktop QR strategy)
  modalOptions: {
    theme: 'auto',              // 'dark' | 'light' | 'auto'
    viewMode: 'toggle',         // 'toggle' | 'dual' | 'pre-step'
    title: 'Scan to Verify',    // Custom title text
    description: '',            // Optional subtitle
    showCloseButton: true,      // Show X button
    closeOnBackdropClick: true, // Close on outside click
    closeOnEscape: true,        // Close on Escape key
  }
});

Modal Customization

The SDK provides a built-in modal for desktop QR code display.

View Modes

| Mode | Description | Best For | |------|-------------|----------| | toggle | Single QR with iOS/Android switch | Clean, minimal UI (default) | | dual | Side-by-side QR codes | Users who may not know their OS | | pre-step | OS selection screen first | Guided experience |

Themes

| Theme | Description | |-------|-------------| | auto | Follows system preference (default) | | dark | Dark background with light text | | light | Light background with dark text |

Custom UI

To use your own UI instead of the built-in modal:

const result = await client.invokeSecurePrompt(prepared, {
  preventDefaultUI: true
});

// For desktop strategy, display your own QR code
if (result.strategy === 'desktop') {
  // Access QR data from the prepare response
  const qrData = prepared.data;
  displayYourQRCode(qrData.ios_qr_image, qrData.android_qr_image);
  
  // Wait for credential
  const credential = await result.credential;
  
  // Or cancel if needed
  result.cancel?.();
}

Authentication Strategies

The SDK automatically selects the best strategy based on the device:

| Strategy | Platform | Description | |----------|----------|-------------| | ts43 | Android Chrome 128+ | Native Digital Credentials API | | link | iOS / Android | App Clip (iOS) or carrier app (Android) | | desktop | Desktop browsers | QR code scanned by mobile |

Strategy-Specific Handling

const result = await client.invokeSecurePrompt(prepared);

switch (result.strategy) {
  case 'ts43':
    // Android: Credential returned directly
    const credential = await result.credential;
    break;
    
  case 'link':
    // iOS: Opens App Clip, polls for completion
    // Android: Opens carrier's privileged app, polls for completion
    const credential = await result.credential;
    // Optionally cancel polling
    result.cancel?.();
    break;
    
  case 'desktop':
    // Desktop: Shows QR modal, polls for completion
    const credential = await result.credential;
    result.cancel?.();
    break;
}

Framework Integration

React

import { usePhoneAuth, USE_CASE } from '@glideidentity/glide-fe-sdk-web/react';

function PhoneVerification() {
  const { authenticate, isLoading, error, result } = usePhoneAuth({
    endpoints: {
      prepare: '/api/magical-auth/prepare',
      reportInvocation: '/api/magical-auth/report-invocation',
      process: '/api/magical-auth/process',
    }
  });

  const handleVerify = async () => {
    try {
      const result = await authenticate({
        use_case: USE_CASE.VERIFY_PHONE_NUMBER,
        phone_number: '+14155551234'
      });
      console.log('Verified:', result.verified);
    } catch (err) {
      console.error('Failed:', err);
    }
  };

  return (
    <button onClick={handleVerify} disabled={isLoading}>
      {isLoading ? 'Verifying...' : 'Verify Phone'}
    </button>
  );
}

Vue

<script setup>
import { usePhoneAuth, USE_CASE } from '@glideidentity/glide-fe-sdk-web/vue';

const { authenticate, isLoading, error, result } = usePhoneAuth({
  endpoints: {
    prepare: '/api/magical-auth/prepare',
    reportInvocation: '/api/magical-auth/report-invocation',
    process: '/api/magical-auth/process',
  }
});

const handleVerify = async () => {
  await authenticate({
    use_case: USE_CASE.VERIFY_PHONE_NUMBER,
    phone_number: '+14155551234'
  });
};
</script>

<template>
  <button @click="handleVerify" :disabled="isLoading">
    {{ isLoading ? 'Verifying...' : 'Verify Phone' }}
  </button>
</template>

Vanilla JavaScript (Browser)

<script src="https://unpkg.com/@glideidentity/glide-fe-sdk-web/dist/browser/web-client-sdk.min.js"></script>
<script>
  const { PhoneAuthClient, USE_CASE } = GlideWebClientSDK;
  
  const client = new PhoneAuthClient({
    endpoints: {
      prepare: '/api/magical-auth/prepare',
      reportInvocation: '/api/magical-auth/report-invocation',
      process: '/api/magical-auth/process',
    }
  });
  
  document.getElementById('verify-btn').onclick = async () => {
    const result = await client.authenticate({
      use_case: USE_CASE.VERIFY_PHONE_NUMBER,
      phone_number: '+14155551234'
    });
    console.log('Verified:', result.verified);
  };
</script>

Advanced Features

Custom HTTP Headers

Add custom headers to all SDK requests:

const client = new PhoneAuthClient({
  endpoints: { ... },
  headers: {
    common: {
      'X-Custom-Header': 'your-value'
    }
  }
});

Custom Logger

Provide your own logger implementation:

const client = new PhoneAuthClient({
  endpoints: { ... },
  logger: {
    debug: (msg, data) => console.debug('[SDK]', msg, data),
    info: (msg, data) => console.info('[SDK]', msg, data),
    warn: (msg, data) => console.warn('[SDK]', msg, data),
    error: (msg, data) => console.error('[SDK]', msg, data),
  }
});

Custom HTTP Client

Bring your own HTTP client for full control:

const client = new PhoneAuthClient({
  endpoints: { ... },
  httpClient: {
    post: async (url, body, options) => {
      const response = await yourHttpLib.post(url, body, options);
      return response.data;
    },
    get: async (url, options) => {
      const response = await yourHttpLib.get(url, options);
      return response.data;
    }
  }
});

Core Package

For advanced use cases, you can import just the types and validators without the full client:

import { 
  // Types
  type PrepareRequest,
  type PrepareResponse,
  type InvokeResult,
  type SessionInfo,
  
  // Constants
  USE_CASE,
  AUTHENTICATION_STRATEGY,
  ERROR_CODES,
  
  // Validators
  validatePhoneNumber,
  validatePlmn,
  
  // Type Guards
  isTS43Strategy,
  isLinkStrategy,
  isDesktopStrategy,
  isAuthError,
} from '@glideidentity/glide-fe-sdk-web/core';

// Use validators
const { valid, error } = validatePhoneNumber('+14155551234');

// Use type guards
if (isDesktopStrategy(result)) {
  // TypeScript knows result has desktop-specific properties
}

Error Handling

import { ERROR_CODES, isAuthError } from '@glideidentity/glide-fe-sdk-web';

try {
  await client.authenticate({ ... });
} catch (error) {
  if (isAuthError(error)) {
    switch (error.code) {
      case ERROR_CODES.USER_CANCELLED:
        // User closed the modal or cancelled
        break;
      case ERROR_CODES.TIMEOUT:
        // Authentication timed out
        break;
      case ERROR_CODES.NETWORK_ERROR:
        // Network request failed
        break;
      default:
        // Handle other errors
        console.error(error.message);
    }
  }
}

Type Reference

Use Cases

type UseCase = 'GetPhoneNumber' | 'VerifyPhoneNumber';

// Or use the constant
USE_CASE.GET_PHONE_NUMBER    // 'GetPhoneNumber'
USE_CASE.VERIFY_PHONE_NUMBER // 'VerifyPhoneNumber'

Prepare Request

interface PrepareRequest {
  use_case: UseCase;
  phone_number?: string;      // Required for VerifyPhoneNumber
  parent_session_id?: string; // For cross-device flows
}

Invoke Result

interface InvokeResult {
  strategy: 'ts43' | 'link' | 'desktop';
  session: SessionInfo;
  credential: Promise<string>;  // Resolves to credential token
  cancel?: () => void;          // Available for link and desktop
  invocationReport: Promise<{ success: boolean; error?: string }>;
}

ASR Tracking (reportInvocation)

The SDK automatically tracks authentication attempts for Authentication Success Rate (ASR) metrics. This is handled via the reportInvocation endpoint.

Behavior

| Aspect | Description | |--------|-------------| | Fire-and-forget | Never blocks the main authentication flow | | Non-critical | Auth succeeds even if reporting fails | | Observable | Developers CAN check if it worked (optional) | | No latency impact | User doesn't wait for this API call |

Configuration

The reportInvocation endpoint is included in the default config:

const client = new PhoneAuthClient({
  endpoints: {
    prepare: '/api/magical-auth/prepare',
    process: '/api/magical-auth/process',
    reportInvocation: '/api/magical-auth/report-invocation',  // ASR tracking (default)
  }
});

Monitoring (Optional)

If you want to monitor whether ASR tracking succeeded:

const result = await client.invokeSecurePrompt(prepared);

// Main flow continues immediately
const credential = await result.credential;

// Optional: Check report status (doesn't block)
result.invocationReport?.then(({ success, error }) => {
  if (!success) {
    console.warn('ASR tracking failed:', error);
    // Optionally send to your own analytics
  }
});

Backend Endpoint

Your backend should implement a simple pass-through endpoint:

// POST /api/magical-auth/report-invocation
app.post('/api/magical-auth/report-invocation', async (req, res) => {
  const { session_id } = req.body;
  
  try {
    const result = await glide.magicalAuth.reportInvocation({ session_id });
    res.json({ success: result.success });
  } catch (error) {
    // Always return HTTP 200 - never fail the auth flow
    res.json({ success: false, error: error.message });
  }
});

Responses

interface GetPhoneNumberResponse {
  phone_number: string;
  aud?: string;               // Audience from carrier
  sim_swap?: SimSwapInfo;     // SIM swap detection info
  device_swap?: DeviceSwapInfo; // Device swap (IMEI change) detection info
}

interface VerifyPhoneNumberResponse {
  phone_number: string;
  verified: boolean;
  aud?: string;               // Audience from carrier
  sim_swap?: SimSwapInfo;     // SIM swap detection info
  device_swap?: DeviceSwapInfo; // Device swap (IMEI change) detection info
}

SIM Swap Detection

The SDK returns SIM swap detection information when available from carriers. This helps identify potential fraud.

Response Fields

interface SimSwapInfo {
  /** Whether the SIM swap check completed successfully */
  checked: boolean;
  /** Risk level based on SIM change recency */
  risk_level?: 'RISK_LEVEL_HIGH' | 'RISK_LEVEL_MEDIUM' | 'RISK_LEVEL_LOW' | 'RISK_LEVEL_UNKNOWN';
  /** Human-readable time since last SIM change (e.g., "0-4 hours", "more than 3 years") */
  age_band?: string;
  /** When the check was performed (RFC3339) */
  checked_at?: string;
  /** Reason for failure if checked=false */
  reason?: 'timeout' | 'carrier_not_supported' | 'disabled' | 'error';
}

Risk Levels

| Level | Description | Recommended Action | |-------|-------------|-------------------| | RISK_LEVEL_HIGH | SIM changed within 7 days | Block or require additional verification | | RISK_LEVEL_MEDIUM | SIM changed 7-30 days ago | Consider step-up authentication | | RISK_LEVEL_LOW | SIM changed 30+ days ago | Normal processing | | RISK_LEVEL_UNKNOWN | Could not determine | Use default policy |

Helper Functions

import { 
  isHighRiskSimSwap,
  isMediumOrHighRiskSimSwap,
  wasSimSwapChecked,
  getMinDaysSinceSimSwap,
} from '@glideidentity/glide-fe-sdk-web';

const result = await client.getPhoneNumber(credential, session);

// Check if SIM swap was checked
if (wasSimSwapChecked(result.sim_swap)) {
  // Check risk level
  if (isHighRiskSimSwap(result.sim_swap)) {
    // High risk - recent SIM change
    requireAdditionalVerification();
  } else if (isMediumOrHighRiskSimSwap(result.sim_swap)) {
    // Medium risk - consider step-up auth
    showWarning();
  }
  
  // Get minimum days since SIM change
  const minDays = getMinDaysSinceSimSwap(result.sim_swap);
  console.log(`SIM unchanged for at least ${minDays} days`);
}

Device Swap Detection

The SDK returns device swap (IMEI change) detection information when available from carriers. This is a parallel, independent signal alongside SIM swap detection. Not all carriers support this signal — the device_swap field is only present when the carrier provides it.

Response Fields

interface DeviceSwapInfo {
  /** Whether the device swap check completed successfully */
  checked: boolean;
  /** Risk level based on device change recency */
  risk_level?: 'RISK_LEVEL_HIGH' | 'RISK_LEVEL_MEDIUM' | 'RISK_LEVEL_LOW' | 'RISK_LEVEL_UNKNOWN';
  /** Human-readable time since last device (IMEI) change (e.g., "0-4 hours", "more than 3 years") */
  age_band?: string;
  /** When the check was performed (RFC3339) */
  checked_at?: string;
  /** Reason for failure if checked=false */
  reason?: 'timeout' | 'carrier_not_supported' | 'disabled' | 'error';
}

Risk Levels

| Level | Description | Recommended Action | |-------|-------------|-------------------| | RISK_LEVEL_HIGH | Device changed within 7 days | Block or require additional verification | | RISK_LEVEL_MEDIUM | Device changed 7-30 days ago | Consider step-up authentication | | RISK_LEVEL_LOW | Device changed 30+ days ago | Normal processing | | RISK_LEVEL_UNKNOWN | Could not determine | Use default policy |

Helper Functions

import { 
  isHighRiskDeviceSwap,
  isMediumOrHighRiskDeviceSwap,
  wasDeviceSwapChecked,
  getMinDaysSinceDeviceSwap,
} from '@glideidentity/glide-fe-sdk-web';

const result = await client.getPhoneNumber(credential, session);

// Check if device swap was checked
if (wasDeviceSwapChecked(result)) {
  // Check risk level
  if (isHighRiskDeviceSwap(result)) {
    // High risk - recent device change
    requireAdditionalVerification();
  } else if (isMediumOrHighRiskDeviceSwap(result)) {
    // Medium risk - consider step-up auth
    showWarning();
  }
  
  // Get minimum days since device change
  const minDays = getMinDaysSinceDeviceSwap(result);
  console.log(`Device unchanged for at least ${minDays} days`);
}

Browser Support

| Browser | Strategy | Requirements | |---------|----------|--------------| | Chrome Android 128+ | TS43 | Digital Credentials API | | Safari iOS | Link | App Clips support | | Chrome/Edge/Firefox Desktop | Desktop | Any modern version |

Support

License

MIT