@equinor/fusion-framework-module-msal-node
Version:
Fusion Framework module for secure Azure AD authentication in Node.js using MSAL. Supports interactive, silent, and token-only authentication modes with encrypted token storage.
225 lines (161 loc) • 7.9 kB
Markdown
`@equinor/fusion-framework-module-msal-node` provides secure Azure AD authentication for Node.js applications using Microsoft's MSAL (Microsoft Authentication Library). Perfect for CLI tools, background services, and automated processes that need to authenticate with Microsoft services.
## Features
- **Multiple Authentication Modes**: Choose the right auth flow for your use case
- **Secure Token Storage**: Encrypted credential storage using platform keychains
- **Easy Integration**: Simple API that works seamlessly with Fusion Framework
- **Token Management**: Automatic token refresh and caching
- **Cross-Platform**: Works on Windows, macOS, and Linux
- **Zero Configuration**: Sensible defaults with optional customization
## Quick Start
```bash
pnpm add @equinor/fusion-framework-module-msal-node
```
```typescript
import { enableAuthModule } from '@equinor/fusion-framework-module-msal-node';
import { ModulesConfigurator } from '@equinor/fusion-framework-module';
const configurator = new ModulesConfigurator();
enableAuthModule(configurator, (builder) => {
builder.setMode('interactive');
builder.setClientId('your-client-id');
builder.setTenantId('your-tenant-id');
});
const framework = await initialize();
const token = await framework.auth.acquireAccessToken({
scopes: ['https://graph.microsoft.com/.default']
});
```
## Authentication Modes
Choose the authentication mode that best fits your application's needs:
| Mode | Description | Best For | User Interaction |
|------|-------------|----------|------------------|
| **`token_only`** | Uses a pre-provided access token | CI/CD pipelines, serverless functions | None |
| **`silent`** | Uses cached credentials for background auth | Background services, scheduled tasks | None |
| **`interactive`** | Browser-based login with local server | CLI tools, development, user-facing apps | Required |
### When to Use Each Mode
- **`token_only`**: When you already have a valid access token (e.g., from environment variables, CI/CD secrets)
- **`silent`**: When you need background authentication without user interaction (e.g., scheduled jobs, background services)
- **`interactive`**: When you need user login (e.g., CLI tools, development environments, user-facing applications)
## Secure Token Storage
The module uses `@azure/msal-node-extensions` for enterprise-grade security:
- **🔒 Platform Keychains**: Windows Credential Manager, macOS Keychain, Linux libsecret
- **🔐 Encryption at Rest**: Tokens encrypted using platform-specific mechanisms
- **🔄 Automatic Refresh**: Seamless token renewal without user intervention
- **🌐 Cross-Platform**: Consistent security across Windows, macOS, and Linux
## Usage Examples
### Token-Only Mode (CI/CD)
Perfect for automated processes where you already have a valid token:
```typescript
import { enableAuthModule } from '@equinor/fusion-framework-module-msal-node';
import { ModulesConfigurator } from '@equinor/fusion-framework-module';
const configurator = new ModulesConfigurator();
enableAuthModule(configurator, (builder) => {
builder.setMode('token_only');
builder.setAccessToken(process.env.ACCESS_TOKEN); // From CI/CD secrets
});
const framework = await initialize();
const token = await framework.auth.acquireAccessToken({
scopes: ['https://graph.microsoft.com/.default']
});
```
### Silent Mode (Background Services)
For background services that need to authenticate without user interaction:
```typescript
import { enableAuthModule } from '@equinor/fusion-framework-module-msal-node';
import { ModulesConfigurator } from '@equinor/fusion-framework-module';
const configurator = new ModulesConfigurator();
enableAuthModule(configurator, (builder) => {
builder.setMode('silent');
builder.setClientId(process.env.AZURE_CLIENT_ID);
builder.setTenantId(process.env.AZURE_TENANT_ID);
});
const framework = await initialize();
// This will use cached credentials or fail if no valid cache exists
try {
const token = await framework.auth.acquireAccessToken({
scopes: ['https://graph.microsoft.com/.default']
});
console.log('Authenticated successfully');
} catch (error) {
console.error('Silent authentication failed:', error.message);
}
```
### Interactive Mode (CLI Tools)
For CLI tools and development environments that require user login:
```typescript
import { enableAuthModule } from '@equinor/fusion-framework-module-msal-node';
import { ModulesConfigurator } from '@equinor/fusion-framework-module';
const configurator = new ModulesConfigurator();
enableAuthModule(configurator, (builder) => {
builder.setMode('interactive');
builder.setClientId(process.env.AZURE_CLIENT_ID);
builder.setTenantId(process.env.AZURE_TENANT_ID);
builder.setServerPort(3000); // Optional: custom port
builder.setServerOnOpen((url) => {
console.log(`🌐 Please open your browser and navigate to: ${url}`);
});
});
const framework = await initialize();
// This will open a browser for user login
const result = await framework.auth.login({
scopes: ['https://graph.microsoft.com/.default']
});
console.log('Login successful:', result.account?.username);
```
## Configuration
### Required Settings
| Setting | Description | Required For |
|---------|-------------|--------------|
| `clientId` | Azure AD application client ID | `silent`, `interactive` |
| `tenantId` | Azure AD tenant ID | `silent`, `interactive` |
| `accessToken` | Pre-obtained access token | `token_only` |
### Optional Settings
| Setting | Description | Default | Mode |
|---------|-------------|---------|------|
| `serverPort` | Local server port for auth callbacks | `3000` | `interactive` |
| `serverOnOpen` | Callback when browser opens | `undefined` | `interactive` |
### Environment Variables
```bash
# Required for silent/interactive modes
AZURE_CLIENT_ID=your-client-id
AZURE_TENANT_ID=your-tenant-id
# Required for token_only mode
ACCESS_TOKEN=your-access-token
```
## API Reference
### `enableAuthModule(configurator, configure)`
Enables the MSAL Node module in your Fusion Framework application.
**Parameters:**
- `configurator`: `ModulesConfigurator` - The modules configurator instance
- `configure`: `(builder: IAuthConfigurator) => void` - Configuration function
### `IAuthProvider`
The authentication provider interface available at `framework.auth`:
```typescript
interface IAuthProvider {
// Acquire an access token for the specified scopes
acquireAccessToken(options: {
scopes: string[];
interactive?: boolean
}): Promise<string>;
// Login (interactive mode only)
login(options: { scopes: string[] }): Promise<AuthenticationResult>;
// Logout (interactive mode only)
logout(): Promise<void>;
}
```
## Troubleshooting
### Common Issues
| Issue | Solution |
|-------|----------|
| **Invalid client/tenant ID** | Verify your Azure AD app registration settings |
| **Port already in use** | Change the `serverPort` or kill the process using the port |
| **Silent auth fails** | Ensure you've logged in interactively first to cache credentials |
| **Token expired** | The module handles refresh automatically; check your scopes |
| **Credential storage errors** | See our [credential storage guide](docs/libsecret.md) |
### Getting Help
- 📖 [Credential Storage Troubleshooting](docs/libsecret.md) - Platform-specific setup help
- 🐛 [Report Issues](https://github.com/equinor/fusion/issues) - Bug reports and feature requests
## Additional Resources
- [Microsoft Graph API Documentation](https://docs.microsoft.com/en-us/graph/)
- [Azure AD App Registration Guide](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app)
- [MSAL Node Documentation](https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-node)
- [Fusion Framework Documentation](https://github.com/equinor/fusion-framework)