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/connectOr 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).
2. Add Environment Variables (Recommended)
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/callbackConfiguration Fallback Order:
- Constructor parameters (highest priority)
- Environment variables (
NYLAS_CLIENT_ID,NYLAS_REDIRECT_URI) - Auto-detected values (redirect URI from current hostname in development)
- 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 defaultOr 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
Popup Flow (Recommended)
// 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
Automatic Scope Management (Recommended)
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
localStorageby default (browser only) for persistence across sessions. - Set
persistTokens: falseto use memory-only storage (tokens won't survive page reloads). - Use
getSession,getAccessToken,getUserInfoto 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 scopesMicrosoftScope- Type-safe Microsoft Graph scopesYahooScope- Type-safe Yahoo scopes (legacy support)NylasScope- Union of all supported scopesProviderScopes- 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) |
| 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 levelNYLAS_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*.localdomains- Automatically enables debug logging for easy development
Node.js Detection:
NODE_ENV=developmentorNODE_ENV=devHOSTorHOSTNAMEcontaining "localhost"
Manual Control
Browser Environment:
localStorage.setItem('NYLAS_CONNECT_DEBUG', 'true')- Force enablelocalStorage.setItem('NYLAS_CONNECT_DEBUG', 'false')- Force disable- URL parameter:
?debug=trueor?debug=false
Node.js Environment:
NYLAS_CONNECT_DEBUG=true- Force enableNYLAS_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 offAccess 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
PopupErrordetails
Environment Variables Not Working
- Verify
NYLAS_CLIENT_IDandNYLAS_REDIRECT_URIare 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: trueis 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
redirectUriexactly matches the one configured in Nylas Dashboard - Verify you're using the correct
apiUrlfor your region
Token Expired Errors
- Tokens expire naturally - this is expected behavior
- Use
isConnected()to check status before API calls - Listen to
SESSION_EXPIREDevents 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
- Nylas Docs โ Official API documentation
- Nylas Dashboard โ Manage your apps and credentials
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 coverageNotes:
- Tests run with
environment: happy-domas configured invitest.config.ts. - Minimal polyfills (e.g., Web Crypto,
btoa/atob) are set up invitest.setup.ts.