JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 2258
  • Score
    100M100P100Q118271F
  • License MIT

Modern, lightweight Nylas connection library with PKCE support

Package Exports

  • @nylas/connect

Readme

@nylas/connect

Modern, secure, and developer-friendly authentication for Nylas APIs.


Overview

@nylas/connect is a lightweight, ESM-only TypeScript library for connecting users with Nylas using OAuth2 and PKCE. It supports both popup and redirect (inline) flows, provides smart defaults, and is designed for modern web apps.

  • Zero dependencies
  • Full TypeScript support
  • Works in all modern browsers
  • Automatic session and token management
  • Actionable error messages

๐Ÿš€ Quick Install

npm install @nylas/connect

Or with yarn:

yarn add @nylas/connect

โšก Quick Start

1. Create a Nylas App

  • Go to the Nylas Dashboard and create an application.
  • Note your Client ID and set your Redirect URI (e.g., http://localhost:3000/auth/callback).

Environment variables provide a secure way to configure the auth client without hardcoding credentials:

NYLAS_CLIENT_ID=your-nylas-client-id
NYLAS_REDIRECT_URI=http://localhost:3000/auth/callback

Configuration Fallback Order:

  1. Constructor parameters (highest priority)
  2. Environment variables (NYLAS_CLIENT_ID, NYLAS_REDIRECT_URI)
  3. Auto-detected values (redirect URI from current hostname in development)
  4. Validation errors if required values are missing

3. Initialize the Auth Client

import { NylasConnect } from "@nylas/connect";

const auth = new NylasConnect(); // Uses env vars by default

Or pass config directly (overrides environment variables):

const auth = new NylasConnect({
  clientId: "your-nylas-client-id", // Overrides NYLAS_CLIENT_ID env var
  redirectUri: "http://localhost:3000/auth/callback", // Overrides NYLAS_REDIRECT_URI env var
});

๐Ÿ”‘ Authenticate Users

// Nylas handles default scopes automatically - no scopes needed for basic email/calendar access
const result = await auth.connect({
  method: "popup",
});
console.log("User info:", result.userInfo);

// Or specify custom scopes for specific provider requirements
const result = await auth.connect({
  method: "popup",
  scopes: [
    "https://www.googleapis.com/auth/gmail.readonly",
    "https://www.googleapis.com/auth/calendar.events.readonly",
  ],
});

Redirect (Inline) Flow

// Nylas handles default scopes automatically
const url = await auth.connect({
  method: "inline",
});
window.location.href = url;

// Or with custom scopes
const url = await auth.connect({
  method: "inline",
  scopes: ["https://graph.microsoft.com/Mail.Read"],
});
window.location.href = url;

Universal Callback Handling

On your callback page (e.g., /auth/callback):

import { NylasConnect } from "@nylas/connect";
const auth = new NylasConnect();
const result = await auth.callback();
console.log("Authenticated!", result);

Minimal HTML for Popup Callback

<!doctype html>
<html>
  <head>
    <title>Nylas Auth Callback</title>
  </head>
  <body>
    <script type="module">
      import { NylasConnect } from "@nylas/connect";
      const auth = new NylasConnect();
      auth.callback();
    </script>
  </body>
</html>

๐Ÿ” OAuth Scopes

๐ŸŽฏ Quick Summary

  • โœ… Recommended: Let Nylas handle scopes automatically for most use cases
  • โš™๏ธ Custom Scopes: Override when you need specific permissions or want to limit access
  • ๐Ÿ”ง Provider-Specific: Different providers (Google, Microsoft, IMAP/iCloud) have different scope requirements

Nylas handles OAuth scopes automatically by default. For most use cases, you don't need to specify scopes - Nylas will request the appropriate permissions based on the APIs you use. Simply connect without the scopes parameter:

// Recommended: Let Nylas handle scopes automatically
const result = await auth.connect({ method: "popup" });

Why use automatic scopes?

  • โœ… Simplifies integration - no need to research provider-specific scopes
  • โœ… Future-proof - automatically gets new permissions as APIs evolve
  • โœ… Optimal permissions - requests exactly what you need, nothing more

Custom Scope Management

When you need specific permissions or want to limit access, you can specify scopes manually. Each OAuth provider has different scope formats:

Google Scopes

All Google scopes must be prefixed with https://www.googleapis.com/auth/:

const auth = new NylasConnect({
  clientId: "your-client-id",
  redirectUri: "http://localhost:3000/auth/callback",
  defaultScopes: [
    "https://www.googleapis.com/auth/gmail.readonly", // Read email
    "https://www.googleapis.com/auth/gmail.send", // Send email
    "https://www.googleapis.com/auth/calendar.events.readonly", // Read calendar
    "https://www.googleapis.com/auth/contacts.readonly", // Read contacts
  ],
});

Microsoft Scopes

All Microsoft scopes must be prefixed with https://graph.microsoft.com/:

const auth = new NylasConnect({
  clientId: "your-client-id",
  redirectUri: "http://localhost:3000/auth/callback",
  defaultScopes: [
    "https://graph.microsoft.com/Mail.Read", // Read email
    "https://graph.microsoft.com/Mail.Send", // Send email
    "https://graph.microsoft.com/Calendars.Read", // Read calendar
    "https://graph.microsoft.com/Contacts.Read", // Read contacts
  ],
});

IMAP/ICLOUD Configuration

For IMAP and iCloud connections, authentication flows differ from OAuth providers:

const auth = new NylasConnect({
  clientId: "your-client-id",
  redirectUri: "http://localhost:3000/auth/callback",
  // IMAP and iCloud don't use OAuth scopes -
  // authentication is handled through Nylas Connect flow
});

Provider-Specific Configuration

You can configure different scopes for different providers:

const auth = new NylasConnect({
  clientId: "your-client-id",
  redirectUri: "http://localhost:3000/auth/callback",
  defaultScopes: {
    google: [
      "https://www.googleapis.com/auth/gmail.readonly",
      "https://www.googleapis.com/auth/calendar.events.readonly",
    ],
    microsoft: [
      "https://graph.microsoft.com/Mail.Read",
      "https://graph.microsoft.com/Calendars.Read",
    ],
    // IMAP and iCloud don't use OAuth scopes
    imap: undefined,
    icloud: undefined,
  },
});

Runtime Scope Override

Override scopes at authentication time:

// Override default scopes for this authentication
await auth.connect({
  method: "popup",
  scopes: ["https://www.googleapis.com/auth/gmail.modify"], // More permissive scope
});

Common Scope Patterns

API Feature Google Scope Microsoft Scope IMAP/iCloud
Read Email gmail.readonly Mail.Read No scopes required
Send Email gmail.send Mail.Send No scopes required
Modify Email gmail.modify Mail.ReadWrite No scopes required
Read Calendar calendar.events.readonly Calendars.Read No scopes required
Modify Calendar calendar.events Calendars.ReadWrite No scopes required
Read Contacts contacts.readonly Contacts.Read No scopes required

Note: All Google and Microsoft scopes shown above need their full URI prefix in actual implementation. IMAP and iCloud providers connect through Nylas Connect flow without OAuth scopes.

For complete scope requirements, see the official Nylas scopes documentation.

TypeScript Scope Types

@nylas/connect provides comprehensive TypeScript types for OAuth scopes with full autocompletion support:

import {
  GoogleScope,
  MicrosoftScope,
  YahooScope,
  NylasScope,
  ProviderScopes,
  Provider,
} from "@nylas/connect";

// Type-safe Google scopes
const googleScopes: GoogleScope[] = [
  "https://www.googleapis.com/auth/gmail.readonly",
  "https://www.googleapis.com/auth/calendar.events.readonly",
];

// Type-safe Microsoft scopes
const microsoftScopes: MicrosoftScope[] = [
  "https://graph.microsoft.com/Mail.Read",
  "https://graph.microsoft.com/Calendars.Read",
];

// Type-safe Yahoo scopes (for legacy support)
const yahooScopes: YahooScope[] = ["email", "mail-r"];

// Supported providers
const supportedProviders: Provider[] = [
  "google",
  "microsoft",
  "imap",
  "icloud",
];

// Provider-specific configuration with types
const providerScopes: ProviderScopes = {
  google: ["https://www.googleapis.com/auth/gmail.readonly"],
  microsoft: ["https://graph.microsoft.com/Mail.Read"],
  // IMAP and iCloud don't use OAuth scopes
};

// Universal scope type (accepts any valid scope for OAuth providers)
const anyScope: NylasScope[] = [
  "https://www.googleapis.com/auth/gmail.readonly", // Google
  "https://graph.microsoft.com/Mail.Read", // Microsoft
];

Benefits of Typed Scopes:

  • โœ… Autocompletion: IDE shows available scopes as you type
  • โœ… Type Safety: Prevents typos in scope names
  • โœ… Documentation: Hover to see scope descriptions
  • โœ… Refactoring: Safe renames across your codebase

๐Ÿง  Concepts & Flows

Authentication Flows

Flow Description Best For
Popup Opens a popup window for OAuth login SPAs, seamless UX
Inline Redirects the browser to the OAuth provider Traditional web apps
  • Popup: User stays on your app, a popup handles the OAuth flow.
  • Inline: User is redirected away and back to your app after login.

Session & Token Management

  • Tokens are stored in localStorage by default (browser only) for persistence across sessions.
  • Set persistTokens: false to use memory-only storage (tokens won't survive page reloads).
  • Use getSession, getAccessToken, getUserInfo to access session data.
  • Use logout() to clear tokens and sign out.

Auth State Events

Subscribe to authentication state changes:

auth.onAuthStateChange((event, session) => {
  if (event === "SIGNED_IN") {
    // User signed in
  } else if (event === "SIGNED_OUT") {
    // User signed out
  }
});

๐Ÿ› ๏ธ Common Use Cases

Check if User is Connected

const isConnected = await auth.isConnected();
if (isConnected) {
  // User is connected
}

Get Current User Info

const user = await auth.getUserInfo();
console.log(user);

Logout

await auth.logout();

โš›๏ธ React Hook

For React applications, use the useNylasConnect hook for seamless state management:

import { useNylasConnect, UseNylasConnectConfig } from "@nylas/react";
import { LogLevel } from "@nylas/connect";

function App() {
  const config: UseNylasConnectConfig = {
    clientId: "your-nylas-client-id",
    redirectUri: "http://localhost:3000/auth/callback",
    persistTokens: true, // Optional: control token persistence
    debug: false, // Optional: control initial debug state
    logLevel: LogLevel.INFO, // Optional: set specific log level

    // Hook-specific options
    autoRefreshInterval: 30000, // Auto-refresh every 30 seconds
    initialLoadingState: true, // Start in loading state
    retryAttempts: 2, // Retry failed operations twice
    enableAutoRecovery: true, // Recover from network errors silently
  };

  const {
    isConnected,
    user,
    isLoading,
    error,
    connect,
    logout,
    enableDebug,
    disableDebug,
    setLogLevel,
    logger,
  } = useNylasConnect(config);

  const handleLogin = () => {
    // Nylas handles scopes automatically - no need to specify them
    connect({ method: "popup" });
  };

  const handleLoginWithCustomScopes = () => {
    // Override with custom scopes if needed
    connect({
      method: "popup",
      scopes: ["https://www.googleapis.com/auth/gmail.readonly"],
    });
  };

  const handleEnableLogging = () => {
    enableDebug(); // Enable debug logging
  };

  const handleSetLogLevel = () => {
    setLogLevel(LogLevel.WARN); // Set to warn level using enum
    // Or: setLogLevel("warn"); // String also works
  };

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      {isConnected ? (
        <div>
          <p>Welcome, {user?.name || user?.email}!</p>
          <button onClick={logout}>Logout</button>
          <button onClick={handleEnableLogging}>Enable Debug</button>
          <button onClick={() => setLogLevel("off")}>Disable Logs</button>
        </div>
      ) : (
        <button onClick={handleLogin}>Login with Nylas</button>
      )}
    </div>
  );
}

React Hook Logger Control:

The useNylasConnect hook exposes logger control methods for runtime debugging:

import { LogLevel } from "@nylas/connect";

function DebugControls() {
  const { enableDebug, disableDebug, setLogLevel, logger } =
    useNylasConnect(config);

  return (
    <div>
      <button onClick={enableDebug}>Enable Debug</button>
      <button onClick={disableDebug}>Disable Debug</button>
      <button onClick={() => setLogLevel(LogLevel.INFO)}>Set Info Level</button>
      <button onClick={() => setLogLevel(LogLevel.WARN)}>Set Warn Level</button>
      <button onClick={() => logger.info("Custom log message")}>
        Log Message
      </button>
    </div>
  );
}

Hook Return Values

Property Type Description
isConnected boolean Whether user is connected
user UserInfo | null Current user information
isLoading boolean Loading state for auth operations
error Error | null Any authentication errors
connect function Trigger connection flow
logout function Sign out the current user
refreshSession function Refresh current session
enableDebug function Enable debug logging
disableDebug function Disable debug logging
setLogLevel function Set specific log level
logger object Direct access to logger methods
authClient NylasConnect Access to underlying auth client

Hook Configuration (UseNylasConnectConfig)

The React hook accepts all standard AuthConfig properties plus additional hook-specific options:

Property Type Default Description
autoRefreshInterval number - Auto-refresh session interval in milliseconds
initialLoadingState boolean true Initial loading state when hook mounts
retryAttempts number 0 Number of retry attempts for failed operations
enableAutoRecovery boolean false Enable automatic error recovery for network errors

Examples:

// Basic configuration
const config: UseNylasConnectConfig = {
  clientId: "your-client-id",
  redirectUri: "http://localhost:3000/callback",
};

// With hook-specific features
const config: UseNylasConnectConfig = {
  clientId: "your-client-id",
  redirectUri: "http://localhost:3000/callback",
  autoRefreshInterval: 60000, // Refresh every minute
  retryAttempts: 3, // Retry failed operations
  enableAutoRecovery: true, // Silent error recovery
  initialLoadingState: false, // Don't start loading
};

โš™๏ธ Configuration

Option Type Default Description
clientId string - Nylas Client ID (can be set via NYLAS_CLIENT_ID env var)
redirectUri string - OAuth redirect URI (can be set via NYLAS_REDIRECT_URI env var)
apiUrl string https://api.nylas.com Nylas Auth API URL. Supported regions: https://api.nylas.com (default), https://api.us.nylas.com, https://api.eu.nylas.com
environment Environment auto-detect "development", "staging", "production"
defaultScopes NylasScope[] | ProviderScopes - OAuth scopes (Nylas handles automatically if not specified)
debug boolean true in dev Enable debug logging
logLevel LogLevel | "off" - Set specific log level: "error", "warn", "info", "debug", "off" (overrides debug flag)
persistTokens boolean true Store tokens in localStorage (false = memory only)

๐Ÿ“š API Reference

NylasConnect Methods

Method Returns Description
connect(options?: AuthOptions) Promise<AuthResult | string> Start OAuth2 flow (popup or inline)
callback(url?: string) Promise Universal callback handler (popup/inline)
getSession(grantId?: string) Promise<SessionData | null> Get current session data
getAccessToken(grantId?: string) Promise<string | null> Get stored access token
getUserInfo(grantId?: string) Promise<UserInfo | null> Get stored user info
isConnected(grantId?: string) Promise Is user currently connected?
getConnectionStatus(grantId?:string) Promise Get connection status
logout(grantId?: string) Promise Clear stored tokens and logout
onAuthStateChange(cb) () => void Subscribe to auth state changes

AuthOptions

Option Type Description
method "popup"|"inline" Authentication method (default: "inline")
scopes NylasScope[] Override default scopes (typed for autocompletion)
provider string Specific OAuth provider
loginHint string Email hint for login
state string Custom state parameter
popupWidth number Popup window width (default: 500)
popupHeight number Popup window height (default: 600)

Scope Types Available:

  • GoogleScope - Type-safe Google OAuth scopes
  • MicrosoftScope - Type-safe Microsoft Graph scopes
  • YahooScope - Type-safe Yahoo scopes (legacy support)
  • NylasScope - Union of all supported scopes
  • ProviderScopes - Provider-specific scope configuration

AuthResult

Field Type Description
accessToken string OAuth access token
idToken string ID token (JWT)
grantId string Grant/session ID
expiresAt number Expiration timestamp (ms)
scope string Granted scopes
userInfo object User info from ID token

UserInfo

Field Type Description
id string User ID (sub claim)
email string Email address
name string Display name
picture string Profile picture URL
provider string OAuth provider
emailVerified boolean Email verified flag
givenName string Given name
familyName string Family name

ConnectionStatus

  • "connected"
  • "expired"
  • "invalid"
  • "not_connected"

Auth Events

All authentication events with their descriptions and data payloads:

Event Category Description Data Payload
AUTH_STARTED Authentication Flow When connect() is called { method, provider?, scopes }
AUTH_REDIRECT Authentication Flow When redirecting to OAuth provider { url, provider? }
AUTH_POPUP_OPENED Authentication Flow When popup window opens { url, provider? }
AUTH_POPUP_CLOSED Authentication Flow When popup window closes { reason: "completed" | "cancelled" | "error" }
AUTH_CALLBACK_RECEIVED Authentication Flow When callback URL is processed { code?, state?, error? }
AUTH_SUCCESS Authentication Flow When authentication completes successfully { grantId, provider, scopes }
AUTH_ERROR Authentication Flow When authentication fails { error, step }
AUTH_CANCELLED Authentication Flow When user cancels authentication { reason }
SIGNED_IN Session Management When user becomes connected { session, isNewLogin }
SIGNED_OUT Session Management When user signs out { grantId?, reason }
SESSION_RESTORED Session Management When existing session is found on init { session, fromStorage }
SESSION_EXPIRED Session Management When session expires naturally { grantId, expiresAt }
SESSION_INVALID Session Management When session is found to be invalid { grantId, reason }
TOKEN_REFRESHED Token Management When access token is refreshed { grantId, newExpiresAt }
TOKEN_REFRESH_ERROR Token Management When token refresh fails { grantId, error }
TOKEN_VALIDATION_ERROR Token Management When token validation fails { grantId, error }
USER_UPDATED User & Profile When user info changes { userInfo, changes }
USER_PROFILE_LOADED User & Profile When user profile is fetched { userInfo, source }
CONNECTION_STATUS_CHANGED Connection & Network When connection status changes { status, previousStatus, grantId? }
NETWORK_ERROR Connection & Network When network requests fail { operation, error }
STORAGE_ERROR Storage When storage operations fail { operation, key, error }
STORAGE_CLEARED Storage When auth storage is cleared { reason }

Example Usage:

auth.onAuthStateChange((event, session, data) => {
  switch (event) {
    case "AUTH_STARTED":
      console.log(`Authentication started with ${data.method} method`);
      break;
    case "AUTH_SUCCESS":
      console.log(`Authentication successful for provider: ${data.provider}`);
      break;
    case "SESSION_EXPIRED":
      console.log(`Session expired at ${new Date(data.expiresAt)}`);
      break;
    case "NETWORK_ERROR":
      console.error(`Network error during ${data.operation}:`, data.error);
      break;
  }
});

Error Types & Utilities

The library exports structured error types and utility functions for advanced use cases:

Error Types

All errors extend the base AuthError interface with structured information:

import {
  NylasConnectError,
  ConfigError,
  NetworkError,
  OAuthError,
  TokenError,
  PopupError,
} from "@nylas/connect";

try {
  await auth.connect();
} catch (error) {
  if (error instanceof ConfigError) {
    // Configuration/setup issues
    console.error("Config issue:", error.message);
    console.log("Fix:", error.fix);
  } else if (error instanceof OAuthError) {
    // OAuth flow/authorization issues
    console.error("OAuth error:", error.message);
  } else if (error instanceof NetworkError) {
    // Network or API communication errors
    console.error("Network error:", error.message);
  } else if (error instanceof TokenError) {
    // Token parsing/validation errors
    console.error("Token error:", error.message);
  } else if (error instanceof PopupError) {
    // Popup-specific errors (blocked, closed, etc.)
    console.error("Popup error:", error.message);
  }
}

Utility Functions

import { parseAuthCallback, isAuthCallback } from "@nylas/connect";

// Check if current URL contains OAuth callback parameters
if (isAuthCallback()) {
  // Parse callback data from URL
  const callbackData = parseAuthCallback();
  console.log(callbackData); // { code?, state?, error? }
}

Storage Classes

For advanced storage scenarios, you can access the storage implementations:

import { BrowserTokenStorage, MemoryTokenStorage } from "@nylas/connect";

// These are used internally based on persistTokens setting
const browserStorage = new BrowserTokenStorage(); // localStorage-based
const memoryStorage = new MemoryTokenStorage(); // memory-only

๐Ÿ“ Logging

The library includes a built-in logger with configurable log levels that can be controlled via environment variables or programmatically.

Log Levels

  • debug: Shows all messages (debug, info, warn, error)
  • info: Shows info, warn, and error messages
  • warn: Shows warn and error messages
  • error: Shows only error messages
  • off: Disables all logging

Smart Logging Behavior

Default Behavior:

  • Production: Logger is disabled by default (secure and performant)
  • Localhost/Development: Logger auto-enables at debug level for easy development
  • Explicit Control: Environment variables override automatic detection
    • NYLAS_CONNECT_DEBUG=true: Forces debug level
    • NYLAS_CONNECT_DEBUG=false: Forces disabled

Automatic Localhost Detection

The logger automatically detects development environments and enables debug logging:

Browser Detection:

  • localhost, 127.0.0.1, ::1, or *.local domains
  • Automatically enables debug logging for easy development

Node.js Detection:

  • NODE_ENV=development or NODE_ENV=dev
  • HOST or HOSTNAME containing "localhost"

Manual Control

Browser Environment:

  • localStorage.setItem('NYLAS_CONNECT_DEBUG', 'true') - Force enable
  • localStorage.setItem('NYLAS_CONNECT_DEBUG', 'false') - Force disable
  • URL parameter: ?debug=true or ?debug=false

Node.js Environment:

  • NYLAS_CONNECT_DEBUG=true - Force enable
  • NYLAS_CONNECT_DEBUG=false - Force disable

Programmatic Control

import { NylasConnect, LogLevel } from "@nylas/connect";

const auth = new NylasConnect();

// Enable debug logging (shows all messages)
auth.enableDebug();

// Disable all logging
auth.disableDebug();

// Set specific log level using enum values
auth.setLogLevel(LogLevel.WARN); // Only warn and error messages
auth.setLogLevel(LogLevel.DEBUG); // All messages
auth.setLogLevel("off"); // No messages

// Or use string values (also supported)
auth.setLogLevel("warn");
auth.setLogLevel("debug");
auth.setLogLevel("info");
auth.setLogLevel("error");

Configuration-based logging:

import { NylasConnect, LogLevel } from "@nylas/connect";

// Set log level during initialization (overrides debug flag)
const auth = new NylasConnect({
  clientId: "your-nylas-client-id",
  redirectUri: "http://localhost:3000/auth/callback",
  logLevel: LogLevel.INFO, // Set specific log level using enum
  // Or use string: logLevel: "info"
});

// Or use debug flag for simple on/off control
const auth = new NylasConnect({
  clientId: "your-nylas-client-id",
  redirectUri: "http://localhost:3000/auth/callback",
  debug: false, // Disable logging
});

Using the Logger Directly

import { logger, LogLevel } from "@nylas/connect";

// The logger provides standard log levels
logger.debug("Debug information");
logger.info("General information");
logger.warn("Warning message");
logger.error("Error message");
logger.log("Alias for info - backward compatibility");

// Control the logger directly
logger.setLevel(LogLevel.DEBUG); // Using enum
logger.setLevel("debug"); // Or using string
logger.enable(); // Sets to debug level
logger.disable(); // Sets to off

Access logger from auth instance:

const auth = new NylasConnect({ clientId, redirectUri });

// Access logger methods through the auth instance
auth.logger.info("Custom log message");
auth.logger.debug("Debug info");
auth.logger.setLevel("warn");
auth.logger.enable();
auth.logger.disable();

All log messages include timestamps and are prefixed with [NYLAS-AUTH] for easy identification.


๐Ÿงฉ Advanced Usage

Token Storage Control

By default, @nylas/connect stores authentication tokens in localStorage, which means sessions persist across page reloads and browser restarts. You can control this behavior using the persistTokens option:

Memory-Only Storage (No Persistence)

const auth = new NylasConnect({
  clientId: "your-nylas-client-id",
  redirectUri: "http://localhost:3000/auth/callback",
  persistTokens: false, // Tokens stored in memory only
});

Use Cases:

  • Enhanced Security: Tokens don't persist if user leaves browser open
  • Temporary Sessions: Perfect for kiosks, shared computers, or demo environments
  • Testing: Clean state between test runs

Behavior:

  • โœ… OAuth flow works normally (temporary state still uses localStorage for reliability)
  • โœ… Users can connect and use the app during their session
  • โŒ Sessions don't survive page reloads or browser restarts
  • โŒ Users need to re-connect after navigation/refresh

Persistent Storage (Default)

const auth = new NylasConnect({
  clientId: "your-nylas-client-id",
  redirectUri: "http://localhost:3000/auth/callback",
  persistTokens: true, // Default behavior - can be omitted
});

Behavior:

  • โœ… Sessions persist across page reloads and browser restarts
  • โœ… Better user experience for typical web applications
  • โœ… Users stay signed in until token expires or manual logout

Storage Implementations

The library provides two built-in storage implementations that are automatically selected based on your persistTokens setting:

import { BrowserTokenStorage, MemoryTokenStorage } from "@nylas/connect";

// BrowserTokenStorage - uses localStorage (default when persistTokens: true)
const browserStorage = new BrowserTokenStorage();

// MemoryTokenStorage - uses in-memory storage (used when persistTokens: false)
const memoryStorage = new MemoryTokenStorage();

Note: Storage selection is automatic based on the persistTokens configuration. Custom storage implementations are not currently supported through the constructor, but the storage interfaces are exported for advanced use cases.


๐Ÿ›ก๏ธ Error Handling

All errors are structured and provide actionable suggestions and documentation links:

try {
  await auth.connect();
} catch (error) {
  console.error("Error:", error.message);
  console.log("Fix:", error.fix); // Actionable suggestion
  console.log("Docs:", error.docsUrl); // Link to relevant docs
}
Error Type Description
ConfigError Configuration/setup issue
OAuthError OAuth flow/authorization issue
NetworkError Network or API communication error
TokenError Token parsing/validation error

๐Ÿ”„ Migration from @nylas/identity

Note: Package Renamed This package was previously named @nylas/auth and has been renamed to @nylas/connect. All functionality remains the same - only the package name has changed. If you're upgrading from @nylas/auth, simply update your import statements and package.json dependency.

The new @nylas/connect library is a complete rewrite with breaking changes:

Change Description
Simplified API Single connect() method for all flows
Promise-based All methods return Promises
Modern/Zero Dependencies No runtime dependencies
ESM Only No CommonJS support
TypeScript First Full TypeScript support

Before (@nylas/identity)

import { NylasSessions } from "@nylas/identity";
const sessions = new NylasSessions({ clientId, redirectUri });
await sessions.auth({ popup: true });

After (@nylas/connect)

import { NylasConnect } from "@nylas/connect";
const auth = new NylasConnect({ clientId, redirectUri });
await auth.connect({ method: "popup" });

๐Ÿ”ง Troubleshooting

Common Issues

Authentication Popup Blocked

  • Ensure popup blockers are disabled
  • Call connect() directly from user interaction (click handler)
  • Check browser console for PopupError details

Environment Variables Not Working

  • Verify NYLAS_CLIENT_ID and NYLAS_REDIRECT_URI are set correctly
  • In browser: variables must be prefixed with VITE_, REACT_APP_, etc. depending on your build tool
  • Check the configuration fallback order in the Environment Variables section

Session Not Persisting

  • Check if persistTokens: true is set (default)
  • Verify localStorage is available and not disabled
  • Check browser dev tools โ†’ Application โ†’ Local Storage

CORS Errors

  • Ensure your domain is added to allowed origins in Nylas Dashboard
  • Check if redirectUri exactly matches the one configured in Nylas Dashboard
  • Verify you're using the correct apiUrl for your region

Token Expired Errors

  • Tokens expire naturally - this is expected behavior
  • Use isConnected() to check status before API calls
  • Listen to SESSION_EXPIRED events for automatic handling

Debug Mode

Enable debug logging to troubleshoot issues:

import { NylasConnect, LogLevel } from "@nylas/connect";

const auth = new NylasConnect({
  clientId: "your-client-id",
  redirectUri: "http://localhost:3000/auth/callback",
  debug: true, // Enable debug logs
  logLevel: LogLevel.DEBUG, // Or use enum for specific level
});

// Listen to all auth events for debugging
auth.onAuthStateChange((event, session, data) => {
  console.log("Auth Event:", event, data);
});

๐Ÿ“– Further Reading


License

MIT


๐Ÿงช Running Tests

This package uses Vitest with a browser-like environment provided by happy-dom.

  • Install deps (workspace root):
pnpm install
  • Run the test suite once:
pnpm -w --filter @nylas/connect test
  • Run in watch mode during development:
pnpm -w --filter @nylas/connect test:watch
  • Generate coverage:
pnpm -w --filter @nylas/connect coverage

Notes:

  • Tests run with environment: happy-dom as configured in vitest.config.ts.
  • Minimal polyfills (e.g., Web Crypto, btoa/atob) are set up in vitest.setup.ts.