Analytics Module

Complete API reference for sso.analytics module - retrieve login and authentication analytics, track user patterns, and monitor service usage.

Updated Dec 16, 2025
Edit on GitHub
analytics metrics reporting sdk-module

Analytics Module

The Analytics module provides methods to retrieve login and authentication analytics for your organization. Track user authentication patterns, monitor service usage, and analyze OAuth provider adoption programmatically.

Overview

All analytics methods require authentication and that the authenticated user is a member of the organization being queried. The module provides time-series data, aggregated statistics, and recent event listings.

Module: sso.analytics

Authentication: Required (JWT token must be set)

Default Behavior:

  • Date-ranged methods default to the last 30 days when dates are not specified
  • All dates use YYYY-MM-DD format
  • Results are returned as arrays of typed objects

Methods

getLoginTrends()

Retrieve daily login counts grouped by date. Returns a time series of authentication events useful for visualizing login activity trends over time.

Signature:

getLoginTrends(
  orgSlug: string,
  params?: AnalyticsQuery
): Promise<LoginTrendPoint[]>

Parameters:

Parameter Type Required Description
orgSlug string Yes Organization slug
params AnalyticsQuery No Optional query parameters
params.start_date string No Start date in YYYY-MM-DD format (defaults to 30 days ago)
params.end_date string No End date in YYYY-MM-DD format (defaults to today)

Returns:

Promise<LoginTrendPoint[]> - Array of login trend data points

LoginTrendPoint Interface:

interface LoginTrendPoint {
  date: string;   // Date in YYYY-MM-DD format
  count: number;  // Total number of logins on this date
}

Example:

import { SsoClient } from '@drmhse/sso-sdk';

const sso = new SsoClient({
  baseURL: 'https://authos.example.com',
  token: 'your-jwt-token'
});

// Get login trends for the last 30 days (default)
const trends = await sso.analytics.getLoginTrends('acme-corp');

trends.forEach(point => {
  console.log(`${point.date}: ${point.count} logins`);
});
// Output:
// 2025-01-01: 45 logins
// 2025-01-02: 52 logins
// 2025-01-03: 38 logins

// Get login trends for a specific date range
const januaryTrends = await sso.analytics.getLoginTrends('acme-corp', {
  start_date: '2025-01-01',
  end_date: '2025-01-31'
});

console.log(`Total days with activity: ${januaryTrends.length}`);
console.log(`Total logins: ${januaryTrends.reduce((sum, p) => sum + p.count, 0)}`);

React Example:

import { useState, useEffect } from 'react';
import { SsoClient, LoginTrendPoint } from '@drmhse/sso-sdk';

function LoginTrendsChart({ orgSlug, ssoClient }: {
  orgSlug: string;
  ssoClient: SsoClient;
}) {
  const [trends, setTrends] = useState<LoginTrendPoint[]>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchTrends() {
      try {
        const data = await ssoClient.analytics.getLoginTrends(orgSlug, {
          start_date: '2025-01-01',
          end_date: '2025-01-31'
        });
        setTrends(data);
      } catch (error) {
        console.error('Failed to fetch login trends:', error);
      } finally {
        setLoading(false);
      }
    }

    fetchTrends();
  }, [orgSlug, ssoClient]);

  if (loading) return <div>Loading trends...</div>;

  return (
    <div>
      <h2>Login Trends - January 2025</h2>
      <ul>
        {trends.map(point => (
          <li key={point.date}>
            {point.date}: {point.count} logins
          </li>
        ))}
      </ul>
    </div>
  );
}

Throws:

  • SsoApiError with status 401 - Not authenticated
  • SsoApiError with status 403 - User is not a member of the organization
  • SsoApiError with status 404 - Organization not found

getLoginsByService()

Get login counts grouped by service. Shows which services in your organization have the most authentication activity.

Signature:

getLoginsByService(
  orgSlug: string,
  params?: AnalyticsQuery
): Promise<LoginsByService[]>

Parameters:

Parameter Type Required Description
orgSlug string Yes Organization slug
params AnalyticsQuery No Optional query parameters
params.start_date string No Start date in YYYY-MM-DD format (defaults to 30 days ago)
params.end_date string No End date in YYYY-MM-DD format (defaults to today)

Returns:

Promise<LoginsByService[]> - Array of login counts per service

LoginsByService Interface:

interface LoginsByService {
  service_id: string;    // Unique identifier (UUID) of the service
  service_name: string;  // Display name of the service
  count: number;         // Total number of logins for this service
}

Example:

import { SsoClient } from '@drmhse/sso-sdk';

const sso = new SsoClient({
  baseURL: 'https://authos.example.com',
  token: 'your-jwt-token'
});

// Get logins by service for the last 30 days
const byService = await sso.analytics.getLoginsByService('acme-corp');

// Sort by most-used services
const sorted = byService.sort((a, b) => b.count - a.count);

console.log('Top 3 most-used services:');
sorted.slice(0, 3).forEach((service, index) => {
  console.log(`${index + 1}. ${service.service_name}: ${service.count} logins`);
});
// Output:
// 1. Main Application: 1247 logins
// 2. Mobile App: 856 logins
// 3. Admin Dashboard: 234 logins

// Get logins for a specific quarter
const q1Data = await sso.analytics.getLoginsByService('acme-corp', {
  start_date: '2025-01-01',
  end_date: '2025-03-31'
});

const totalLogins = q1Data.reduce((sum, s) => sum + s.count, 0);
console.log(`Q1 Total Logins: ${totalLogins}`);

React Example:

import { useState, useEffect } from 'react';
import { SsoClient, LoginsByService } from '@drmhse/sso-sdk';

function ServiceUsageChart({ orgSlug, ssoClient }: {
  orgSlug: string;
  ssoClient: SsoClient;
}) {
  const [services, setServices] = useState<LoginsByService[]>([]);

  useEffect(() => {
    async function fetchData() {
      const data = await ssoClient.analytics.getLoginsByService(orgSlug);
      // Sort by usage
      setServices(data.sort((a, b) => b.count - a.count));
    }

    fetchData();
  }, [orgSlug, ssoClient]);

  const totalLogins = services.reduce((sum, s) => sum + s.count, 0);

  return (
    <div>
      <h2>Service Usage (Last 30 Days)</h2>
      <p>Total Logins: {totalLogins}</p>
      <table>
        <thead>
          <tr>
            <th>Service</th>
            <th>Logins</th>
            <th>Percentage</th>
          </tr>
        </thead>
        <tbody>
          {services.map(service => (
            <tr key={service.service_id}>
              <td>{service.service_name}</td>
              <td>{service.count}</td>
              <td>{((service.count / totalLogins) * 100).toFixed(1)}%</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

Throws:

  • SsoApiError with status 401 - Not authenticated
  • SsoApiError with status 403 - User is not a member of the organization
  • SsoApiError with status 404 - Organization not found

getLoginsByProvider()

Get login counts grouped by OAuth provider. Shows which authentication providers (GitHub, Google, Microsoft) are being used by your users.

Signature:

getLoginsByProvider(
  orgSlug: string,
  params?: AnalyticsQuery
): Promise<LoginsByProvider[]>

Parameters:

Parameter Type Required Description
orgSlug string Yes Organization slug
params AnalyticsQuery No Optional query parameters
params.start_date string No Start date in YYYY-MM-DD format (defaults to 30 days ago)
params.end_date string No End date in YYYY-MM-DD format (defaults to today)

Returns:

Promise<LoginsByProvider[]> - Array of login counts per OAuth provider

LoginsByProvider Interface:

interface LoginsByProvider {
  provider: 'github' | 'google' | 'microsoft';  // OAuth provider name
  count: number;                                 // Total number of logins using this provider
}

Example:

import { SsoClient } from '@drmhse/sso-sdk';

const sso = new SsoClient({
  baseURL: 'https://authos.example.com',
  token: 'your-jwt-token'
});

// Get logins by provider for the last 30 days
const byProvider = await sso.analytics.getLoginsByProvider('acme-corp');

byProvider.forEach(provider => {
  console.log(`${provider.provider}: ${provider.count} logins`);
});
// Output:
// github: 1523 logins
// google: 892 logins
// microsoft: 234 logins

// Calculate provider adoption percentages
const total = byProvider.reduce((sum, p) => sum + p.count, 0);
console.log('\nProvider Adoption:');
byProvider.forEach(provider => {
  const percentage = ((provider.count / total) * 100).toFixed(1);
  console.log(`${provider.provider}: ${percentage}%`);
});

// Get provider usage for a specific month
const decemberData = await sso.analytics.getLoginsByProvider('acme-corp', {
  start_date: '2024-12-01',
  end_date: '2024-12-31'
});

const mostPopular = decemberData.reduce((prev, current) =>
  current.count > prev.count ? current : prev
);
console.log(`Most popular provider in December: ${mostPopular.provider}`);

React Example:

import { useState, useEffect } from 'react';
import { SsoClient, LoginsByProvider } from '@drmhse/sso-sdk';

function ProviderDistribution({ orgSlug, ssoClient }: {
  orgSlug: string;
  ssoClient: SsoClient;
}) {
  const [providers, setProviders] = useState<LoginsByProvider[]>([]);

  useEffect(() => {
    async function fetchData() {
      const data = await ssoClient.analytics.getLoginsByProvider(orgSlug);
      setProviders(data);
    }

    fetchData();
  }, [orgSlug, ssoClient]);

  const totalLogins = providers.reduce((sum, p) => sum + p.count, 0);

  const providerColors: Record<string, string> = {
    github: '#333',
    google: '#4285F4',
    microsoft: '#00A4EF'
  };

  return (
    <div>
      <h2>OAuth Provider Distribution</h2>
      <div className="provider-stats">
        {providers.map(provider => {
          const percentage = ((provider.count / totalLogins) * 100).toFixed(1);
          return (
            <div
              key={provider.provider}
              className="provider-card"
              style={{ borderLeft: `4px solid ${providerColors[provider.provider]}` }}
            >
              <h3>{provider.provider}</h3>
              <p className="count">{provider.count} logins</p>
              <p className="percentage">{percentage}%</p>
            </div>
          );
        })}
      </div>
    </div>
  );
}

Throws:

  • SsoApiError with status 401 - Not authenticated
  • SsoApiError with status 403 - User is not a member of the organization
  • SsoApiError with status 404 - Organization not found

getRecentLogins()

Get the most recent login events for your organization. Returns detailed information about individual authentication events, useful for monitoring real-time activity and security auditing.

Signature:

getRecentLogins(
  orgSlug: string,
  params?: AnalyticsQuery
): Promise<RecentLogin[]>

Parameters:

Parameter Type Required Description
orgSlug string Yes Organization slug
params AnalyticsQuery No Optional query parameters
params.limit number No Maximum number of login events to return (defaults to 10)

Returns:

Promise<RecentLogin[]> - Array of recent login events, ordered by most recent first

RecentLogin Interface:

interface RecentLogin {
  id: string;          // Unique identifier (UUID) of the login event
  user_id: string;     // Unique identifier of the user who logged in
  service_id: string;  // Unique identifier (UUID) of the service
  provider: string;    // OAuth provider used (github, google, microsoft)
  created_at: string;  // ISO 8601 timestamp of when the login occurred
}

Example:

import { SsoClient } from '@drmhse/sso-sdk';

const sso = new SsoClient({
  baseURL: 'https://authos.example.com',
  token: 'your-jwt-token'
});

// Get the 10 most recent logins (default)
const recentLogins = await sso.analytics.getRecentLogins('acme-corp');

console.log('Recent Authentication Activity:');
recentLogins.forEach(login => {
  const timestamp = new Date(login.created_at).toLocaleString();
  console.log(`${timestamp} - User ${login.user_id} via ${login.provider}`);
});
// Output:
// 1/15/2025, 2:32:18 PM - User user_123abc via github
// 1/15/2025, 2:28:45 PM - User user_456def via google
// 1/15/2025, 2:15:22 PM - User user_789ghi via microsoft

// Get the 50 most recent logins for detailed monitoring
const extended = await sso.analytics.getRecentLogins('acme-corp', {
  limit: 50
});

// Analyze provider distribution in recent activity
const providerCounts: Record<string, number> = {};
extended.forEach(login => {
  providerCounts[login.provider] = (providerCounts[login.provider] || 0) + 1;
});

console.log('Recent activity by provider:', providerCounts);
// Output: { github: 25, google: 18, microsoft: 7 }

React Example (Real-time Activity Feed):

import { useState, useEffect } from 'react';
import { SsoClient, RecentLogin } from '@drmhse/sso-sdk';

function ActivityFeed({ orgSlug, ssoClient }: {
  orgSlug: string;
  ssoClient: SsoClient;
}) {
  const [logins, setLogins] = useState<RecentLogin[]>([]);
  const [refreshInterval, setRefreshInterval] = useState(10000); // 10 seconds

  useEffect(() => {
    async function fetchRecentLogins() {
      const data = await ssoClient.analytics.getRecentLogins(orgSlug, {
        limit: 20
      });
      setLogins(data);
    }

    // Initial fetch
    fetchRecentLogins();

    // Poll for updates
    const interval = setInterval(fetchRecentLogins, refreshInterval);

    return () => clearInterval(interval);
  }, [orgSlug, ssoClient, refreshInterval]);

  const formatTime = (timestamp: string) => {
    const date = new Date(timestamp);
    const now = new Date();
    const diffMs = now.getTime() - date.getTime();
    const diffMins = Math.floor(diffMs / 60000);

    if (diffMins < 1) return 'Just now';
    if (diffMins < 60) return `${diffMins}m ago`;
    if (diffMins < 1440) return `${Math.floor(diffMins / 60)}h ago`;
    return date.toLocaleDateString();
  };

  const providerIcons: Record<string, string> = {
    github: '🐙',
    google: '🔍',
    microsoft: '🪟'
  };

  return (
    <div className="activity-feed">
      <div className="feed-header">
        <h2>Recent Authentication Activity</h2>
        <button onClick={() => setRefreshInterval(i => i === 10000 ? 30000 : 10000)}>
          {refreshInterval === 10000 ? 'Slow refresh' : 'Fast refresh'}
        </button>
      </div>
      <ul className="login-list">
        {logins.map(login => (
          <li key={login.id} className="login-item">
            <span className="provider-icon">
              {providerIcons[login.provider]}
            </span>
            <div className="login-details">
              <strong>User {login.user_id}</strong>
              <span className="provider-name">via {login.provider}</span>
            </div>
            <time className="login-time">
              {formatTime(login.created_at)}
            </time>
          </li>
        ))}
      </ul>
    </div>
  );
}

Security Monitoring Example:

// Monitor for suspicious activity (e.g., rapid logins from different providers)
async function monitorSuspiciousActivity(
  orgSlug: string,
  ssoClient: SsoClient
) {
  const recentLogins = await ssoClient.analytics.getRecentLogins(orgSlug, {
    limit: 100
  });

  // Group logins by user
  const userLogins: Record<string, RecentLogin[]> = {};
  recentLogins.forEach(login => {
    if (!userLogins[login.user_id]) {
      userLogins[login.user_id] = [];
    }
    userLogins[login.user_id].push(login);
  });

  // Check for suspicious patterns
  Object.entries(userLogins).forEach(([userId, logins]) => {
    // Multiple providers in short time
    const uniqueProviders = new Set(logins.map(l => l.provider));
    if (uniqueProviders.size >= 2 && logins.length > 5) {
      console.warn(`Suspicious: User ${userId} used ${uniqueProviders.size} providers in ${logins.length} logins`);
    }

    // High frequency logins
    if (logins.length > 10) {
      const first = new Date(logins[logins.length - 1].created_at);
      const last = new Date(logins[0].created_at);
      const diffMinutes = (last.getTime() - first.getTime()) / 60000;

      if (diffMinutes < 5) {
        console.warn(`Suspicious: User ${userId} logged in ${logins.length} times in ${diffMinutes.toFixed(1)} minutes`);
      }
    }
  });
}

Throws:

  • SsoApiError with status 401 - Not authenticated
  • SsoApiError with status 403 - User is not a member of the organization
  • SsoApiError with status 404 - Organization not found

Type Definitions

AnalyticsQuery

Query parameters for analytics methods.

interface AnalyticsQuery {
  start_date?: string;  // Start date in YYYY-MM-DD format
  end_date?: string;    // End date in YYYY-MM-DD format
  limit?: number;       // Maximum number of results (for getRecentLogins)
}

Common Patterns

Building Analytics Dashboards

import { SsoClient } from '@drmhse/sso-sdk';

async function fetchAllAnalytics(orgSlug: string, ssoClient: SsoClient) {
  // Fetch all analytics data in parallel
  const [trends, byService, byProvider, recent] = await Promise.all([
    ssoClient.analytics.getLoginTrends(orgSlug),
    ssoClient.analytics.getLoginsByService(orgSlug),
    ssoClient.analytics.getLoginsByProvider(orgSlug),
    ssoClient.analytics.getRecentLogins(orgSlug, { limit: 20 })
  ]);

  return { trends, byService, byProvider, recent };
}

// Usage in a React dashboard
function AnalyticsDashboard({ orgSlug, ssoClient }) {
  const [analytics, setAnalytics] = useState(null);

  useEffect(() => {
    fetchAllAnalytics(orgSlug, ssoClient).then(setAnalytics);
  }, [orgSlug, ssoClient]);

  if (!analytics) return <div>Loading...</div>;

  return (
    <div className="dashboard">
      <LoginTrendsChart data={analytics.trends} />
      <ServiceUsageChart data={analytics.byService} />
      <ProviderDistribution data={analytics.byProvider} />
      <ActivityFeed data={analytics.recent} />
    </div>
  );
}

Custom Date Ranges

import { SsoClient } from '@drmhse/sso-sdk';

// Helper to format dates as YYYY-MM-DD
function formatDate(date: Date): string {
  return date.toISOString().split('T')[0];
}

// Last 7 days
const lastWeek = {
  start_date: formatDate(new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)),
  end_date: formatDate(new Date())
};

const weeklyTrends = await sso.analytics.getLoginTrends('acme-corp', lastWeek);

// Current month
const now = new Date();
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
const thisMonth = {
  start_date: formatDate(monthStart),
  end_date: formatDate(now)
};

const monthlyData = await sso.analytics.getLoginsByService('acme-corp', thisMonth);

// Last quarter
const quarterEnd = new Date();
const quarterStart = new Date(quarterEnd);
quarterStart.setMonth(quarterStart.getMonth() - 3);

const quarterlyProvider = await sso.analytics.getLoginsByProvider('acme-corp', {
  start_date: formatDate(quarterStart),
  end_date: formatDate(quarterEnd)
});

Error Handling

import { SsoClient, SsoApiError } from '@drmhse/sso-sdk';

async function fetchAnalyticsSafely(orgSlug: string, ssoClient: SsoClient) {
  try {
    const trends = await ssoClient.analytics.getLoginTrends(orgSlug);
    return { success: true, data: trends };
  } catch (error) {
    if (error instanceof SsoApiError) {
      if (error.status === 403) {
        return {
          success: false,
          error: 'You do not have permission to view analytics for this organization'
        };
      }
      if (error.status === 404) {
        return {
          success: false,
          error: 'Organization not found'
        };
      }
    }

    return {
      success: false,
      error: 'Failed to fetch analytics data'
    };
  }
}