UNPKG

atko-cross-app-access-sdk

Version:

SDK for Okta Cross-App Access using Identity Assertion Authorization Grant (ID-JAG)

275 lines (211 loc) โ€ข 7.92 kB
# Atko Cross-App Access SDK A TypeScript/JavaScript SDK for implementing **Identity Assertion Authorization Grant (ID-JAG)** with Okta, enabling secure cross-application access patterns. ## Overview This SDK implements the **ID-JAG** (Identity Assertion Authorization Grant) flow as defined in OAuth 2.0 extensions, allowing applications to exchange Okta ID tokens for specialized access tokens that can be used for cross-app authorization. ## Key Features - ๐Ÿ”„ **Token Exchange**: Convert Okta ID tokens to ID-JAG tokens - ๐Ÿ›ก๏ธ **Secure**: Follows OAuth 2.0 Token Exchange (RFC 8693) standards - ๐ŸŽฏ **Cross-App Access**: Enable secure application-to-application communication - ๐Ÿ“ฆ **TypeScript**: Full TypeScript support with type definitions - ๐Ÿงช **Testing**: Built-in test utilities and examples ## Installation ### Stable Release ```bash npm install atko-cross-app-access-sdk ``` ### Beta Release (Latest Features) ```bash npm install atko-cross-app-access-sdk@beta ``` > **Note**: This is currently a beta release. For production use, please wait for the stable 1.0.0 release or thoroughly test the beta version in your environment. ## Quick Start ### Basic Usage ```typescript import { exchangeIdTokenForIdJag } from 'atko-cross-app-access-sdk'; const idJagToken = await exchangeIdTokenForIdJag({ subject_token: 'your-okta-id-token', audience: 'http://localhost:5001', client_id: '0oap6a3kputUHyW1R1d7', client_secret: 'your-client-secret' }, 'https://your-domain.oktapreview.com'); // Explicit Okta domain required console.log('ID-JAG Token:', idJagToken.access_token); ``` ### Using the SDK Class ```typescript import { AtkoCrossAppAccessSDK } from 'atko-cross-app-access-sdk'; const sdk = new AtkoCrossAppAccessSDK('https://your-domain.oktapreview.com'); const result = await sdk.exchangeIdTokenForIdJag({ subject_token: idToken, audience: 'http://your-target-app', client_id: 'your-client-id', client_secret: 'your-client-secret' }); ``` ### Token Verification ```typescript import { verifyIdJagToken } from 'atko-cross-app-access-sdk'; // Verify an ID-JAG token const verificationResult = await verifyIdJagToken(idJagToken, { issuer: 'https://your-domain.oktapreview.com', audience: 'http://localhost:5001' }); if (verificationResult.valid) { console.log('Token is valid!'); console.log('Subject:', verificationResult.sub); console.log('Email:', verificationResult.email); } else { console.log('Token verification failed:', verificationResult.error); } ``` ## API Reference ### `exchangeIdTokenForIdJag(request: IdJagTokenRequest, oktaBaseUrl: string): Promise<IdJagTokenResponse>` Exchanges an Okta ID token for an ID-JAG token. **Parameters:** - `request` (object): - `subject_token` (string): The Okta ID token to exchange - `audience` (string): Target audience/application URL - `client_id` (string): Okta application client ID - `client_secret` (string): Okta application client secret - `oktaBaseUrl` (string): Your Okta domain URL (e.g., "https://your-domain.oktapreview.com") **Returns:** ```typescript { access_token: string; // The ID-JAG token issued_token_type: string; // "urn:ietf:params:oauth:token-type:id-jag" token_type: string; // "Bearer" expires_in?: number; // Token expiration in seconds scope?: string; // Token scope } ``` ### `verifyIdJagToken(token: string, options: IdJagTokenVerificationOptions): Promise<IdJagTokenVerificationResult>` Verifies an ID-JAG token using the issuer's public keys (JWKS). **Parameters:** - `token` (string): The ID-JAG token to verify - `options` (object): - `issuer` (string): Expected token issuer (your Okta domain URL) - `audience` (string): Expected token audience (e.g., "http://localhost:5001") - `jwksUri` (string, optional): JWKS URI, defaults to issuer + "/oauth2/v1/keys" **Returns:** ```typescript { valid: boolean; payload?: any; // Full JWT payload if valid sub?: string; // Subject claim email?: string; // Email claim aud?: string; // Audience claim iss?: string; // Issuer claim exp?: number; // Expiration timestamp error?: string; // Error message if invalid } ``` ## Token Exchange Flow ```mermaid sequenceDiagram participant App as Client App participant Okta as Okta Authorization Server participant Target as Target Application App->>Okta: 1. Authenticate & get ID token App->>SDK: 2. exchangeIdTokenForIdJag(id_token, audience, client_id, secret) SDK->>Okta: 3. POST /oauth2/v1/token (Token Exchange) Okta->>SDK: 4. ID-JAG token SDK->>App: 5. Return ID-JAG token App->>Target: 6. Use ID-JAG token for cross-app access ``` ## Testing ### Manual Testing 1. **Update test configuration:** ```javascript // In test-id-jag.js const TEST_CONFIG = { subject_token: 'YOUR_ACTUAL_ID_TOKEN', audience: 'http://localhost:5001', client_id: '0oap6a3kputUHyW1R1d7', client_secret: 'YOUR_ACTUAL_CLIENT_SECRET' }; ``` 2. **Run the test:** ```bash npm test ``` ### Curl Example The SDK implements this curl command programmatically: ```bash curl --location 'https://ijtestcustom.oktapreview.com/oauth2/v1/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \ --data-urlencode 'requested_token_type=urn:ietf:params:oauth:token-type:id-jag' \ --data-urlencode 'subject_token=YOUR_ID_TOKEN' \ --data-urlencode 'subject_token_type=urn:ietf:params:oauth:token-type:id_token' \ --data-urlencode 'audience=http://localhost:5001' \ --data-urlencode 'client_id=0oap6a3kputUHyW1R1d7' \ --data-urlencode 'client_secret=YOUR_SECRET' ``` ## Integration Examples ### With Express.js Application ```typescript import express from 'express'; import { exchangeIdTokenForIdJag } from 'atko-cross-app-access-sdk'; const app = express(); app.post('/cross-app-access', async (req, res) => { try { const { idToken } = req.body; const idJagToken = await exchangeIdTokenForIdJag({ subject_token: idToken, audience: 'http://target-service:5001', client_id: process.env.OKTA_CLIENT_ID, client_secret: process.env.OKTA_CLIENT_SECRET }); // Use the ID-JAG token to access target service res.json({ success: true, token: idJagToken.access_token }); } catch (error) { res.status(400).json({ error: error.message }); } }); ``` ### With MCP Authorization Server ```typescript // In your MCP auth server import { validateIdJagToken } from 'atko-cross-app-access-sdk'; app.post('/oauth/token', async (req, res) => { const { id_jag_token } = req.body; if (validateIdJagToken(id_jag_token)) { // Issue MCP access token const mcpToken = await generateMcpAccessToken(id_jag_token); res.json({ access_token: mcpToken }); } else { res.status(401).json({ error: 'Invalid ID-JAG token' }); } }); ``` ## Error Handling The SDK provides detailed error messages for common issues: ```typescript try { const result = await exchangeIdTokenForIdJag(config); } catch (error) { if (error.message.includes('invalid_client')) { console.error('Invalid client credentials'); } else if (error.message.includes('invalid_grant')) { console.error('Invalid or expired ID token'); } else { console.error('Token exchange failed:', error.message); } } ``` ## Standards Compliance - **RFC 8693**: OAuth 2.0 Token Exchange - **RFC 6749**: OAuth 2.0 Authorization Framework - **OpenID Connect Core 1.0**: ID Token specifications ## Development ```bash # Install dependencies npm install # Build the project npm run build # Run in development mode npm run dev # Clean build artifacts npm run clean ``` ## License MIT License - see LICENSE file for details.