
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
@lanonasis/oauth-client
Advanced tools
OAuth and API Key authentication client for Lan Onasis MCP integration
THE single authentication package for the Lanonasis ecosystem. Consolidates all auth patterns: OAuth2 PKCE, API keys, magic links, React hooks, and Express middleware.
v2.0: Now includes
/reactand/serverexports! Migrating from@lanonasis/shared-auth? See Migration Guide.
/react)useSSO(): React hook for SSO authentication stateuseSSOSync(): Cross-subdomain session synchronizationparseUserCookie, hasSessionCookie, clearUserCookie/server)requireAuth(): Express middleware enforcing authenticationoptionalAuth(): Attach user if authenticated, allow anonymousrequireRole(role): Role-based access control middlewaregetSSOUserFromRequest, getSessionTokenFromRequestnpm install @lanonasis/oauth-client
# or
bun add @lanonasis/oauth-client
import { MCPClient } from '@lanonasis/oauth-client'; // or '@lanonasis/oauth-client/browser' in web-only bundles
// Simple API key mode - perfect for dashboard users
const client = new MCPClient({
apiKey: 'lano_abc123xyz', // Get from dashboard
mcpEndpoint: 'wss://mcp.lanonasis.com'
});
await client.connect(); // Automatically uses API key auth
// Make requests
const memories = await client.searchMemories('test query');
import { MCPClient } from '@lanonasis/oauth-client';
const client = new MCPClient({
clientId: 'your_oauth_client_id',
authBaseUrl: 'https://auth.lanonasis.com',
mcpEndpoint: 'wss://mcp.lanonasis.com',
scope: 'memories:read memories:write memories:delete profile' // default if omitted
});
await client.connect(); // Triggers OAuth flow, handles refresh
import { TerminalOAuthFlow } from '@lanonasis/oauth-client';
const flow = new TerminalOAuthFlow({
clientId: 'your_client_id',
authBaseUrl: 'https://auth.lanonasis.com',
scope: 'mcp:read'
});
const tokens = await flow.authenticate();
import { DesktopOAuthFlow } from '@lanonasis/oauth-client';
const flow = new DesktopOAuthFlow({
clientId: 'your_client_id',
authBaseUrl: 'https://auth.lanonasis.com'
});
const tokens = await flow.authenticate();
import { MagicLinkFlow } from '@lanonasis/oauth-client';
const flow = new MagicLinkFlow({
authBaseUrl: 'https://auth.lanonasis.com'
});
// Send OTP to user's email
await flow.sendOTP('user@example.com');
// User enters the code they received
const tokens = await flow.verifyOTP('user@example.com', '123456');
/react)import { useSSO, useSSOSync } from '@lanonasis/oauth-client/react';
function MyComponent() {
const { user, isAuthenticated, isLoading, error } = useSSO({
authGatewayUrl: 'https://auth.lanonasis.com',
projectScope: 'my-app'
});
if (isLoading) return <div>Loading...</div>;
if (!isAuthenticated) return <div>Please log in</div>;
return <div>Hello, {user.email}!</div>;
}
// For cross-subdomain session sync
function App() {
useSSOSync({ pollInterval: 30000 });
return <MyComponent />;
}
/server)import express from 'express';
import {
requireAuth,
optionalAuth,
requireRole,
getSSOUserFromRequest
} from '@lanonasis/oauth-client/server';
const app = express();
// Require authentication
app.get('/api/profile', requireAuth(), (req, res) => {
res.json({ user: req.user });
});
// Optional authentication (attach user if present)
app.get('/api/public', optionalAuth(), (req, res) => {
if (req.user) {
res.json({ message: `Hello ${req.user.email}` });
} else {
res.json({ message: 'Hello guest' });
}
});
// Role-based access control
app.delete('/api/admin/users/:id', requireAuth(), requireRole('admin'), (req, res) => {
// Only admins can reach here
});
// Manual user extraction
app.get('/api/check', (req, res) => {
const user = getSSOUserFromRequest(req);
res.json({ authenticated: !!user });
});
import { TokenStorage } from '@lanonasis/oauth-client';
const storage = new TokenStorage();
await storage.store(tokens);
const restored = await storage.retrieve();
In Node and Electron environments, secure storage now lazy-loads keytar so the ESM bundle can still use the native OS keychain when available. If native keychain access is unavailable, storage falls back to the encrypted local file backend automatically.
import { ApiKeyStorage } from '@lanonasis/oauth-client';
const apiKeys = new ApiKeyStorage();
await apiKeys.store({ apiKey: 'lns_abc123', environment: 'production' });
const apiKey = await apiKeys.getApiKey(); // returns the original key for outbound auth headers
Node/Electron secure storage preserves the original secret value so clients can send it back
in X-API-Key or Authorization headers when talking to remote services.
apiKey (required): Your dashboard-generated API key (starts with lano_).mcpEndpoint (optional): defaults to wss://mcp.lanonasis.com and can also be https://... for SSE.tokenStorage (optional): provide a custom storage adapter; defaults to secure Node storage in Node/Electron and WebCrypto+localStorage in browsers.clientId (required): OAuth client id issued by Lanonasis Auth.authBaseUrl (optional): defaults to https://auth.lanonasis.com.mcpEndpoint (optional): defaults to wss://mcp.lanonasis.com and can also be https://... for SSE.scope (optional): defaults to memories:read memories:write memories:delete profile.autoRefresh (MCPClient): refresh tokens 5 minutes before expiry (default true).Note: Auth mode is automatically detected - if you provide apiKey, it uses API key authentication. If you provide clientId, it uses OAuth.
@lanonasis/oauth-client/browser; modern bundlers will also pick it via the browser export.keytar, open, fs, os, etc.) and use Web Crypto + localStorage for token/API key persistence.npm install && npm test && npm run buildbun auditdist, README.md, and LICENSE are present.npm publish --access public (registry must have 2FA as configured).git tag oauth-client-vX.Y.Z && git push --tagsdist/* compiled CJS/ESM bundles + typesREADME.mdLICENSEThis SDK implements client-side equivalents of the auth-gateway's authentication methods:
| Auth-Gateway Endpoint | SDK Class | Use Case |
|---|---|---|
POST /oauth/device | TerminalOAuthFlow | CLI/terminal apps |
GET /oauth/authorize | DesktopOAuthFlow | Desktop apps (Electron) |
POST /v1/auth/otp/* | MagicLinkFlow | Mobile/passwordless |
X-API-Key header | APIKeyFlow | Server-to-server |
MCPClient | Combined | Auto-detects best method |
See auth-gateway/AUTHENTICATION-METHODS.md for complete server-side documentation.
| Export | Description | Use Case |
|---|---|---|
@lanonasis/oauth-client | Main entry - OAuth flows, MCP client, storage | Node.js CLI, servers |
@lanonasis/oauth-client/browser | Browser-safe bundle (no Node deps) | Web apps, SPAs |
@lanonasis/oauth-client/react | React hooks + browser cookie utils | React/Next.js apps |
@lanonasis/oauth-client/server | Express middleware + server cookie utils | Express/Node servers |
@lanonasis/shared-auth is now deprecated. All functionality has been consolidated into @lanonasis/oauth-client.
// ❌ BEFORE (deprecated)
import { useSSO, useSSOSync } from '@lanonasis/shared-auth';
import { getSSOUserFromRequest } from '@lanonasis/shared-auth/server';
// ✅ AFTER (recommended)
import { useSSO, useSSOSync } from '@lanonasis/oauth-client/react';
import { getSSOUserFromRequest, requireAuth } from '@lanonasis/oauth-client/server';
{
"dependencies": {
// ❌ Remove
"@lanonasis/shared-auth": "^1.x.x",
// ✅ Add/Update
"@lanonasis/oauth-client": "^2.0.0"
}
}
The migration gives you access to new middleware that wasn't in shared-auth:
import { requireAuth, optionalAuth, requireRole } from '@lanonasis/oauth-client/server';
// These are new! Replace manual auth checks
app.get('/api/protected', requireAuth(), handler);
app.delete('/api/admin/*', requireAuth(), requireRole('admin'), handler);
MIT © Lan Onasis
FAQs
OAuth and API Key authentication client for Lan Onasis MCP integration
We found that @lanonasis/oauth-client demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.