Skip to main content

GeoLocationService

Package: @nauth-toolkit/core Type: Service

Service for IP geolocation using MaxMind GeoIP2 database files. Provides IP to country/city lookup, database management, and automatic reloading capabilities.

import { GeoLocationService } from '@nauth-toolkit/nestjs';

Overview

The GeoLocationService provides IP geolocation using MaxMind GeoIP2 database files (.mmdb). It supports both managed downloads (via MaxMind API) and external database management (via geoipupdate or other tools).

note

Only available when geoLocation.maxMind is configured. Auto-injected by framework when enabled.

Requirements
  • @maxmind/geoip2-node peer dependency must be installed
  • MaxMind license key and account ID (for downloads) OR pre-existing .mmdb files
  • See the Geolocation guide for setup instructions

Methods

getIpGeolocation()

Get geolocation information for an IP address. Looks up the IP in the loaded MaxMind databases and returns country, city, and coordinates if available.

async getIpGeolocation(ip: string): Promise<{
country?: string;
city?: string;
latitude?: number;
longitude?: number;
}>

Parameters

  • ip (string) - IP address to lookup (IPv4 or IPv6)

Returns

Object with optional geolocation fields:

  • country?: string - Two-letter country code (e.g., 'US', 'GB')
  • city?: string - City name in English (e.g., 'London', 'New York')
  • latitude?: number - Geographic latitude
  • longitude?: number - Geographic longitude

Behavior

  • Private IPs (localhost, 192.168.x.x, 10.x.x.x, etc.) return {} without lookup
  • City database is tried first (includes coordinates); falls back to country database
  • If no databases are loaded, returns {}
  • If IP not found in database, returns {}

Errors

None. This method never throws errors - it returns empty object if geolocation is unavailable.

Example

import { Injectable } from '@nestjs/common';
import { GeoLocationService } from '@nauth-toolkit/nestjs';

@Injectable()
export class LocationService {
constructor(private readonly geoLocationService: GeoLocationService) {}

async checkUserLocation(ip: string) {
const geo = await this.geoLocationService.getIpGeolocation(ip);

if (geo.country) {
console.log(`User is from ${geo.city}, ${geo.country}`);
console.log(`Coordinates: ${geo.latitude}, ${geo.longitude}`);
} else {
console.log('Location unknown');
}
}
}

reloadGeoLocationDatabaseFromDisk()

Reload MaxMind database files from disk without downloading. Useful when database files are managed externally (via geoipupdate, container volumes, CI/CD, etc.).

async reloadGeoLocationDatabaseFromDisk(): Promise<void>

Parameters

None

Returns

Promise that resolves when databases are reloaded

Behavior

  • Attempts to load GeoLite2-City.mmdb and GeoLite2-Country.mmdb from configured dbPath
  • Replaces in-memory database readers with newly loaded ones
  • Logs warnings if no database files are found
  • Safe to call repeatedly - if files haven't changed, it just reloads the same data
  • Works with skipDownloads: true configuration

Errors

CodeWhen
VALIDATION_FAILEDMaxMind configuration not provided
VALIDATION_FAILED@maxmind/geoip2-node peer dependency not installed

Example

import { Injectable } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { GeoLocationService } from '@nauth-toolkit/nestjs';

@Injectable()
export class GeoReloadService {
constructor(private readonly geoLocationService: GeoLocationService) {}

// Reload databases daily (after geoipupdate runs)
@Cron('0 1 * * *') // Every day at 1 AM
async reloadDatabases() {
try {
await this.geoLocationService.reloadGeoLocationDatabaseFromDisk();
console.log('MaxMind databases reloaded successfully');
} catch (error) {
console.error('Failed to reload databases:', error);
}
}
}

updateGeoLocationDatabase()

Download the latest MaxMind database files and reload them into memory. Uses distributed locking to prevent concurrent downloads in multi-server deployments.

async updateGeoLocationDatabase(): Promise<void>

Parameters

None

Returns

Promise that resolves when databases are downloaded and reloaded

Behavior

  • Downloads configured editions (default: GeoLite2-City, GeoLite2-Country) from MaxMind
  • Uses distributed locking (lock key: maxmind-db-update-lock, TTL: 5 minutes)
  • Automatically reloads in-memory database readers after download
  • If another process holds the lock, skips download and returns immediately
  • Requires licenseKey and accountId in configuration
  • Throws if skipDownloads: true

Errors

CodeWhen
VALIDATION_FAILEDMaxMind configuration not provided
VALIDATION_FAILED@maxmind/geoip2-node peer dependency not installed
VALIDATION_FAILEDskipDownloads: true is set in configuration
VALIDATION_FAILEDlicenseKey or accountId is missing from configuration

Example

import { Injectable } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { GeoLocationService } from '@nauth-toolkit/nestjs';

@Injectable()
export class GeoUpdateService {
constructor(private readonly geoLocationService: GeoLocationService) {}

// Update databases weekly
@Cron('0 0 * * 0') // Every Sunday at midnight
async updateMaxMindDatabases() {
try {
await this.geoLocationService.updateGeoLocationDatabase();
console.log('MaxMind databases updated successfully');
} catch (error) {
console.error('Failed to update databases:', error);
}
}
}

Configuration

The GeoLocationService is only available when geoLocation.maxMind is configured. See Geolocation Configuration for all options.

Basic Configuration

import { NAuthModuleConfig } from '@nauth-toolkit/nestjs';

export const authConfig: NAuthModuleConfig = {
// ... other config ...

geoLocation: {
maxMind: {
// For managed downloads
licenseKey: process.env.MAXMIND_LICENSE_KEY,
accountId: parseInt(process.env.MAXMIND_ACCOUNT_ID || '0', 10),
dbPath: '/app/data/maxmind',

// OR for external management
dbPath: '/app/data/maxmind',
skipDownloads: true,
},
},
};

Usage Patterns

Pattern 1: Auto-Download (Development)

Best for development and single-server deployments.

// Config
geoLocation: {
maxMind: {
licenseKey: process.env.MAXMIND_LICENSE_KEY,
accountId: parseInt(process.env.MAXMIND_ACCOUNT_ID || '0', 10),
autoDownloadOnStartup: true,
},
}

// No additional code needed - databases auto-download on startup

Pattern 2: Scheduled Updates (Production)

Best for production with nauth-managed downloads.

// Config
geoLocation: {
maxMind: {
licenseKey: process.env.MAXMIND_LICENSE_KEY,
accountId: parseInt(process.env.MAXMIND_ACCOUNT_ID || '0', 10),
dbPath: '/app/data/maxmind',
},
}

// Service
@Injectable()
export class GeoUpdateService {
constructor(private readonly geoLocationService: GeoLocationService) {}

@Cron('0 0 1 * *') // First day of each month
async updateDatabases() {
await this.geoLocationService.updateGeoLocationDatabase();
}
}

Pattern 3: External Management (Production)

Best for production with external database management (geoipupdate, CI/CD).

// Config
geoLocation: {
maxMind: {
dbPath: '/app/data/maxmind',
skipDownloads: true,
},
}

// Service
@Injectable()
export class GeoReloadService {
constructor(private readonly geoLocationService: GeoLocationService) {}

@Cron('0 1 * * *') // Daily at 1 AM (after geoipupdate)
async reloadDatabases() {
await this.geoLocationService.reloadGeoLocationDatabaseFromDisk();
}
}