Skip to main content

Node.js Backend SDK

Server-side SDK for integrating Glide Identity with Node.js applications.

Installation

npm install glide-sdk
# or
yarn add glide-sdk

Quick Start

import { GlideClient } from 'glide-sdk';

const glide = new GlideClient({
apiKey: process.env.GLIDE_API_KEY,
internal: {
authBaseUrl: 'https://oidc.gateway-x.io',
apiBaseUrl: 'https://api.glideidentity.app'
}
});

// Prepare authentication request
const prepareResponse = await glide.magicAuth.prepare({
use_case: 'VerifyPhoneNumber',
phone_number: '+14155551234',
consent_data: {
consent_text: 'I agree to verify my phone number',
policy_link: 'https://example.com/privacy',
policy_text: 'Privacy Policy'
}
});

// After browser gets credential...

// Verify phone number
const verifyResponse = await glide.magicAuth.verifyPhoneNumber({
session: prepareResponse.session,
credential: credentialFromBrowser
});

// Or get phone number
const getPhoneResponse = await glide.magicAuth.getPhoneNumber({
session: prepareResponse.session,
credential: credentialFromBrowser
});

Express.js Integration

import express from 'express';
import { GlideClient } from 'glide-sdk';

const app = express();
app.use(express.json());

const glide = new GlideClient({
apiKey: process.env.GLIDE_API_KEY,
internal: {
authBaseUrl: process.env.GLIDE_AUTH_BASE_URL || 'https://oidc.gateway-x.io',
apiBaseUrl: process.env.GLIDE_API_BASE_URL || 'https://api.glideidentity.app'
}
});

// Prepare endpoint
app.post('/api/phone-auth/prepare', async (req, res) => {
try {
const response = await glide.magicAuth.prepare(req.body);
res.json(response);
} catch (error) {
console.error('Prepare error:', error);
res.status(error.status || 500).json({
code: error.code || 'INTERNAL_SERVER_ERROR',
message: error.message || 'An error occurred'
});
}
});

// Process endpoint
app.post('/api/phone-auth/process', async (req, res) => {
try {
const { use_case, ...requestBody } = req.body;

if (use_case === 'VerifyPhoneNumber') {
const response = await glide.magicAuth.verifyPhoneNumber(requestBody);
res.json(response);
} else if (use_case === 'GetPhoneNumber') {
const response = await glide.magicAuth.getPhoneNumber(requestBody);
res.json(response);
} else {
res.status(400).json({
code: 'INVALID_USE_CASE',
message: 'Invalid use case'
});
}
} catch (error) {
console.error('Process error:', error);
res.status(error.status || 500).json({
code: error.code || 'INTERNAL_SERVER_ERROR',
message: error.message || 'An error occurred'
});
}
});

app.listen(3000, () => {
console.log('Server running on port 3000');
});

Fastify Integration

import Fastify from 'fastify';
import { GlideClient } from 'glide-sdk';

const fastify = Fastify({ logger: true });

const glide = new GlideClient({
apiKey: process.env.GLIDE_API_KEY
});

// Prepare endpoint
fastify.post('/api/phone-auth/prepare', async (request, reply) => {
try {
const response = await glide.magicAuth.prepare(request.body);
return response;
} catch (error) {
reply.code(error.status || 500);
return {
code: error.code || 'INTERNAL_SERVER_ERROR',
message: error.message
};
}
});

// Process endpoint
fastify.post('/api/phone-auth/process', async (request, reply) => {
try {
const { use_case, ...requestBody } = request.body;

if (use_case === 'VerifyPhoneNumber') {
return await glide.magicAuth.verifyPhoneNumber(requestBody);
} else {
return await glide.magicAuth.getPhoneNumber(requestBody);
}
} catch (error) {
reply.code(error.status || 500);
return {
code: error.code,
message: error.message
};
}
});

await fastify.listen({ port: 3000 });

Koa Integration

import Koa from 'koa';
import Router from '@koa/router';
import bodyParser from 'koa-bodyparser';
import { GlideClient } from 'glide-sdk';

const app = new Koa();
const router = new Router();

const glide = new GlideClient({
apiKey: process.env.GLIDE_API_KEY
});

app.use(bodyParser());

// Prepare endpoint
router.post('/api/phone-auth/prepare', async (ctx) => {
try {
const response = await glide.magicAuth.prepare(ctx.request.body);
ctx.body = response;
} catch (error) {
ctx.status = error.status || 500;
ctx.body = {
code: error.code || 'INTERNAL_SERVER_ERROR',
message: error.message
};
}
});

// Process endpoint
router.post('/api/phone-auth/process', async (ctx) => {
try {
const { use_case, ...requestBody } = ctx.request.body;

if (use_case === 'VerifyPhoneNumber') {
ctx.body = await glide.magicAuth.verifyPhoneNumber(requestBody);
} else {
ctx.body = await glide.magicAuth.getPhoneNumber(requestBody);
}
} catch (error) {
ctx.status = error.status || 500;
ctx.body = {
code: error.code,
message: error.message
};
}
});

app.use(router.routes());
app.listen(3000);

TypeScript Support

import { GlideClient, MagicAuthError } from 'glide-sdk';

interface PrepareRequest {
use_case: 'GetPhoneNumber' | 'VerifyPhoneNumber';
phone_number?: string;
plmn?: {
mcc: string;
mnc: string;
};
consent_data?: {
consent_text: string;
policy_link: string;
policy_text: string;
};
}

const glide = new GlideClient({
apiKey: process.env.GLIDE_API_KEY!
});

async function handlePrepare(request: PrepareRequest) {
try {
const response = await glide.magicAuth.prepare(request);
return response;
} catch (error) {
if (error instanceof MagicAuthError) {
console.error('Magic Auth Error:', error.code, error.message);
}
throw error;
}
}

Error Handling

import { GlideClient, MagicAuthError } from 'glide-sdk';

app.post('/api/phone-auth/prepare', async (req, res) => {
try {
const response = await glide.magicAuth.prepare(req.body);
res.json(response);
} catch (error) {
if (error instanceof MagicAuthError) {
// Handle specific Magic Auth errors
switch (error.code) {
case 'CARRIER_NOT_ELIGIBLE':
res.status(422).json({
code: error.code,
message: 'Your carrier does not support this verification method',
carrier_name: error.details?.carrier_name
});
break;

case 'INVALID_PHONE_NUMBER':
res.status(400).json({
code: error.code,
message: 'Phone number must be in E.164 format'
});
break;

case 'RATE_LIMIT_EXCEEDED':
res.status(429).json({
code: error.code,
message: 'Too many requests',
retry_after: error.details?.retry_after
});
break;

default:
res.status(error.status || 500).json({
code: error.code,
message: error.message
});
}
} else {
// Handle unexpected errors
console.error('Unexpected error:', error);
res.status(500).json({
code: 'INTERNAL_SERVER_ERROR',
message: 'An unexpected error occurred'
});
}
}
});

Environment Variables

# .env
GLIDE_API_KEY=your_api_key_here
GLIDE_AUTH_BASE_URL=https://oidc.gateway-x.io
GLIDE_API_BASE_URL=https://api.glideidentity.app

# For development/testing
GLIDE_ENV=development
GLIDE_LOG_LEVEL=debug

Configuration Options

const glide = new GlideClient({
// Required
apiKey: 'your_api_key',

// Optional
internal: {
authBaseUrl: 'https://oidc.gateway-x.io',
apiBaseUrl: 'https://api.glideidentity.app'
},

// Request timeout in milliseconds (default: 30000)
timeout: 30000,

// Retry configuration
retry: {
maxAttempts: 3,
retryDelay: 1000
},

// Custom logger
logger: {
debug: (msg) => console.debug(msg),
info: (msg) => console.info(msg),
warn: (msg) => console.warn(msg),
error: (msg) => console.error(msg)
}
});

API Methods

magicAuth.prepare(request)

Prepares an authentication request.

const response = await glide.magicAuth.prepare({
use_case: 'VerifyPhoneNumber',
phone_number: '+14155551234',
consent_data: {
consent_text: 'I agree',
policy_link: 'https://example.com/privacy',
policy_text: 'Privacy Policy'
}
});

// Response
{
authentication_strategy: 'ts43',
session: {
session_key: 'sess_abc123',
nonce: 'xyz789',
enc_key: 'enc_key_123'
},
data: { /* strategy-specific data */ }
}

magicAuth.verifyPhoneNumber(request)

Verifies phone number ownership.

const response = await glide.magicAuth.verifyPhoneNumber({
session: sessionFromPrepare,
credential: credentialFromBrowser
});

// Response
{
verified: true,
phone_number: '+14155551234'
}

magicAuth.getPhoneNumber(request)

Retrieves phone number from device.

const response = await glide.magicAuth.getPhoneNumber({
session: sessionFromPrepare,
credential: credentialFromBrowser
});

// Response
{
phone_number: '+14155551234'
}

Next Steps