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'
}