2025-07-16 14:07:30 -04:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html lang="en">
|
|
|
|
<head>
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
<title>PKCE OpenID Flow - No Redirects</title>
|
|
|
|
<style>
|
|
|
|
body {
|
|
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
|
|
max-width: 900px;
|
|
|
|
margin: 0 auto;
|
|
|
|
padding: 20px;
|
|
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
|
min-height: 100vh;
|
|
|
|
}
|
|
|
|
.container {
|
|
|
|
background: white;
|
|
|
|
padding: 30px;
|
|
|
|
border-radius: 12px;
|
|
|
|
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
|
|
|
|
margin-bottom: 20px;
|
|
|
|
}
|
|
|
|
.header {
|
|
|
|
text-align: center;
|
|
|
|
margin-bottom: 30px;
|
|
|
|
color: #333;
|
|
|
|
}
|
|
|
|
.step {
|
|
|
|
margin: 20px 0;
|
|
|
|
padding: 20px;
|
|
|
|
border: 1px solid #e0e0e0;
|
|
|
|
border-radius: 8px;
|
|
|
|
background: #fafafa;
|
|
|
|
}
|
|
|
|
.step.active {
|
|
|
|
border-color: #007bff;
|
|
|
|
background: #f0f8ff;
|
|
|
|
}
|
|
|
|
.step.completed {
|
|
|
|
border-color: #28a745;
|
|
|
|
background: #f0fff0;
|
|
|
|
}
|
|
|
|
.form-group {
|
|
|
|
margin-bottom: 15px;
|
|
|
|
}
|
|
|
|
label {
|
|
|
|
display: block;
|
|
|
|
margin-bottom: 5px;
|
|
|
|
font-weight: 600;
|
|
|
|
color: #555;
|
|
|
|
}
|
|
|
|
input[type="text"], input[type="password"] {
|
|
|
|
width: 100%;
|
|
|
|
padding: 12px;
|
|
|
|
border: 1px solid #ddd;
|
|
|
|
border-radius: 6px;
|
|
|
|
font-size: 14px;
|
|
|
|
box-sizing: border-box;
|
|
|
|
}
|
|
|
|
input[type="text"]:focus, input[type="password"]:focus {
|
|
|
|
outline: none;
|
|
|
|
border-color: #007bff;
|
|
|
|
box-shadow: 0 0 0 2px rgba(0,123,255,0.25);
|
|
|
|
}
|
|
|
|
button {
|
|
|
|
background: #007bff;
|
|
|
|
color: white;
|
|
|
|
border: none;
|
|
|
|
padding: 12px 24px;
|
|
|
|
border-radius: 6px;
|
|
|
|
cursor: pointer;
|
|
|
|
font-size: 14px;
|
|
|
|
margin: 8px 4px;
|
|
|
|
transition: background-color 0.2s;
|
|
|
|
}
|
|
|
|
button:hover { background: #0056b3; }
|
|
|
|
button:disabled {
|
|
|
|
background: #6c757d;
|
|
|
|
cursor: not-allowed;
|
|
|
|
}
|
|
|
|
button.success {
|
|
|
|
background: #28a745;
|
|
|
|
}
|
|
|
|
button.success:hover {
|
|
|
|
background: #218838;
|
|
|
|
}
|
|
|
|
.token-display {
|
|
|
|
background: #f8f9fa;
|
|
|
|
padding: 15px;
|
|
|
|
border-radius: 5px;
|
|
|
|
font-family: 'Courier New', monospace;
|
|
|
|
font-size: 12px;
|
|
|
|
word-break: break-all;
|
|
|
|
margin: 10px 0;
|
|
|
|
border: 1px solid #dee2e6;
|
|
|
|
max-height: 200px;
|
|
|
|
overflow-y: auto;
|
|
|
|
}
|
|
|
|
.status {
|
|
|
|
margin: 15px 0;
|
|
|
|
padding: 12px;
|
|
|
|
border-radius: 6px;
|
|
|
|
font-weight: 500;
|
|
|
|
}
|
|
|
|
.status.success { background: #d4edda; border: 1px solid #c3e6cb; color: #155724; }
|
|
|
|
.status.error { background: #f8d7da; border: 1px solid #f5c6cb; color: #721c24; }
|
|
|
|
.status.info { background: #d1ecf1; border: 1px solid #bee5eb; color: #0c5460; }
|
|
|
|
.spinner {
|
|
|
|
border: 3px solid #f3f3f3;
|
|
|
|
border-top: 3px solid #007bff;
|
|
|
|
border-radius: 50%;
|
|
|
|
width: 20px;
|
|
|
|
height: 20px;
|
|
|
|
animation: spin 1s linear infinite;
|
|
|
|
display: inline-block;
|
|
|
|
margin-right: 10px;
|
|
|
|
}
|
|
|
|
@keyframes spin {
|
|
|
|
0% { transform: rotate(0deg); }
|
|
|
|
100% { transform: rotate(360deg); }
|
|
|
|
}
|
|
|
|
.hidden { display: none; }
|
|
|
|
.iframe-container {
|
|
|
|
border: 2px solid #007bff;
|
|
|
|
border-radius: 8px;
|
|
|
|
margin: 20px 0;
|
|
|
|
background: #f8f9fa;
|
|
|
|
padding: 10px;
|
|
|
|
}
|
|
|
|
.oauth-iframe {
|
|
|
|
width: 100%;
|
|
|
|
height: 400px;
|
|
|
|
border: 1px solid #ddd;
|
|
|
|
border-radius: 4px;
|
|
|
|
background: white;
|
|
|
|
}
|
|
|
|
.final-result {
|
|
|
|
background: #fff3cd;
|
|
|
|
border: 1px solid #ffeaa7;
|
|
|
|
border-radius: 6px;
|
|
|
|
padding: 20px;
|
|
|
|
margin-top: 20px;
|
|
|
|
}
|
|
|
|
.progress {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
margin-bottom: 30px;
|
|
|
|
}
|
|
|
|
.progress-step {
|
|
|
|
flex: 1;
|
|
|
|
text-align: center;
|
|
|
|
padding: 10px;
|
|
|
|
background: #f8f9fa;
|
|
|
|
border: 1px solid #dee2e6;
|
|
|
|
margin: 0 2px;
|
|
|
|
border-radius: 4px;
|
|
|
|
font-size: 12px;
|
|
|
|
}
|
|
|
|
.progress-step.active {
|
|
|
|
background: #007bff;
|
|
|
|
color: white;
|
|
|
|
}
|
|
|
|
.progress-step.completed {
|
|
|
|
background: #28a745;
|
|
|
|
color: white;
|
|
|
|
}
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
.progress-step.clickable {
|
|
|
|
cursor: pointer;
|
|
|
|
transition: background-color 0.2s;
|
|
|
|
}
|
|
|
|
.progress-step.clickable:hover {
|
|
|
|
background: #007bff;
|
|
|
|
color: white;
|
|
|
|
}
|
2025-07-16 14:07:30 -04:00
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="container">
|
|
|
|
<div class="header">
|
|
|
|
<h1>🔐 PKCE OpenID Flow</h1>
|
|
|
|
<p>Complete OpenID Connect authentication with PKCE using iframe (no page redirects)</p>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="progress">
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
<div class="progress-step active clickable" id="step0-progress" onclick="goToStep(0)">0. Config</div>
|
|
|
|
<div class="progress-step clickable" id="step1-progress" onclick="goToStep(1)">1. Login</div>
|
2025-07-16 14:07:30 -04:00
|
|
|
<div class="progress-step" id="step2-progress">2. Session Token</div>
|
|
|
|
<div class="progress-step" id="step3-progress">3. iframe PKCE</div>
|
|
|
|
<div class="progress-step" id="step4-progress">4. OAuth Tokens</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<!-- Step 0: Configuration -->
|
|
|
|
<div class="step active" id="step0">
|
|
|
|
<h3>⚙️ Step 0: Okta Configuration</h3>
|
|
|
|
<p>Configure your Okta environment settings:</p>
|
|
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
<label for="oktaDomain">Okta Domain:</label>
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
<input type="text" id="oktaDomain" name="oktaDomain" value="<YOUR_OKTA_DOMAIN>" required>
|
2025-07-16 14:07:30 -04:00
|
|
|
<small style="color: #666; font-size: 12px;">Example: dev-12345678.okta.com or your-company.okta.com</small>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
<label for="clientId">Client ID:</label>
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
<input type="text" id="clientId" name="clientId" value="<YOUR_OKTA_CLIENT_ID>" required>
|
2025-07-16 14:07:30 -04:00
|
|
|
<small style="color: #666; font-size: 12px;">Your Okta application's client ID</small>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
<label for="redirectUri">Redirect URI:</label>
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
<input type="text" id="redirectUri" name="redirectUri" value="<YOUR_REDIRECT_URI>" required>
|
2025-07-16 14:07:30 -04:00
|
|
|
<small style="color: #666; font-size: 12px;">Must match your Okta app configuration</small>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
<label for="authServerId">Authorization Server ID:</label>
|
|
|
|
<input type="text" id="authServerId" name="authServerId" value="default" required>
|
|
|
|
<small style="color: #666; font-size: 12px;">Usually 'default' or custom authorization server ID</small>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
<h4 style="margin-top: 25px; margin-bottom: 15px; color: #555;">📍 Generated Endpoints:</h4>
|
|
|
|
<div style="background: #f8f9fa; padding: 15px; border-radius: 6px; border: 1px solid #dee2e6;">
|
|
|
|
<div style="margin-bottom: 10px;">
|
|
|
|
<strong>Base URL:</strong><br>
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
<code id="displayBaseUrl">https://<YOUR_OKTA_DOMAIN></code>
|
2025-07-16 14:07:30 -04:00
|
|
|
</div>
|
|
|
|
<div style="margin-bottom: 10px;">
|
|
|
|
<strong>Authorization Endpoint:</strong><br>
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
<code id="displayAuthEndpoint">https://<YOUR_OKTA_DOMAIN>/oauth2/default/v1/authorize</code>
|
2025-07-16 14:07:30 -04:00
|
|
|
</div>
|
|
|
|
<div style="margin-bottom: 10px;">
|
|
|
|
<strong>Token Endpoint:</strong><br>
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
<code id="displayTokenEndpoint">https://<YOUR_OKTA_DOMAIN>/oauth2/default/v1/token</code>
|
2025-07-16 14:07:30 -04:00
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<strong>Authentication API:</strong><br>
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
<code id="displayAuthApi">https://<YOUR_OKTA_DOMAIN>/api/v1/authn</code>
|
2025-07-16 14:07:30 -04:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<button onclick="validateAndSaveConfig()">
|
|
|
|
<span id="configSpinner" class="spinner hidden"></span>
|
|
|
|
<span id="configText">✅ Validate & Save Configuration</span>
|
|
|
|
</button>
|
|
|
|
|
|
|
|
<div style="margin-top: 15px;">
|
|
|
|
<button onclick="loadPresetConfig('demo')" style="background: #6c757d;">
|
|
|
|
📋 Load Demo Config
|
|
|
|
</button>
|
|
|
|
<button onclick="loadPresetConfig('production')" style="background: #6c757d;">
|
|
|
|
🏢 Load Production Template
|
|
|
|
</button>
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
<button onclick="clearConfigFromStorage(); location.reload();" style="background: #dc3545;">
|
|
|
|
🗑️ Clear All & Reset
|
|
|
|
</button>
|
2025-07-16 14:07:30 -04:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<!-- Step 1: Login -->
|
|
|
|
<div class="step hidden" id="step1">
|
|
|
|
<h3>🔐 Step 1: Okta Login</h3>
|
|
|
|
<div class="form-group">
|
|
|
|
<label for="username">Username or Email:</label>
|
|
|
|
<input type="text" id="username" name="username" placeholder="Enter your username or email" required>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
<label for="password">Password:</label>
|
|
|
|
<input type="password" id="password" name="password" placeholder="Enter your password" required>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<button onclick="performLogin()">
|
|
|
|
<span id="loginSpinner" class="spinner hidden"></span>
|
|
|
|
<span id="loginText">🚀 Login to Okta</span>
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<!-- Step 2: Session Token Display -->
|
|
|
|
<div class="step hidden" id="step2">
|
|
|
|
<h3>🎫 Step 2: Session Token Retrieved</h3>
|
|
|
|
<p>Successfully authenticated with Okta!</p>
|
|
|
|
<div class="token-display" id="sessionTokenDisplay"></div>
|
|
|
|
<button onclick="startIframePKCE()" class="success">
|
|
|
|
✅ Continue to iframe PKCE Flow
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<!-- Step 3: iframe PKCE Flow -->
|
|
|
|
<div class="step hidden" id="step3">
|
|
|
|
<h3>🖼️ Step 3: iframe PKCE Authorization</h3>
|
|
|
|
<p>Using iframe to capture authorization code without page redirect:</p>
|
|
|
|
|
|
|
|
<div id="iframeStatus" class="status info">
|
|
|
|
<span class="spinner"></span>
|
|
|
|
<span>Preparing iframe PKCE flow...</span>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="iframe-container hidden" id="iframeContainer">
|
|
|
|
<p><strong>OAuth Authorization in iframe:</strong></p>
|
|
|
|
<iframe id="oauthIframe" class="oauth-iframe" src="about:blank"></iframe>
|
|
|
|
<div class="status info">
|
|
|
|
<span>🔍 Monitoring iframe for authorization code...</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<!-- Step 4: Final Results -->
|
|
|
|
<div class="step hidden" id="finalResults">
|
|
|
|
<h3>🎉 Success! Your OAuth Tokens</h3>
|
|
|
|
|
|
|
|
<h4>Access Token:</h4>
|
|
|
|
<div class="token-display" id="finalAccessToken"></div>
|
|
|
|
<button onclick="copyToken('access')">📋 Copy Access Token</button>
|
|
|
|
<button onclick="decodeToken('access')">🔍 Decode Access Token</button>
|
|
|
|
|
|
|
|
<h4>ID Token:</h4>
|
|
|
|
<div class="token-display" id="finalIdToken"></div>
|
|
|
|
<button onclick="copyToken('id')">📋 Copy ID Token</button>
|
|
|
|
<button onclick="decodeToken('id')">🔍 Decode ID Token</button>
|
|
|
|
|
|
|
|
<div class="final-result">
|
|
|
|
<h4>🌐 Ready for API Integration!</h4>
|
|
|
|
<p><strong>Use this Authorization header:</strong></p>
|
|
|
|
<div class="token-display">Authorization: Bearer <span id="tokenForHeader"></span></div>
|
|
|
|
<button onclick="copyAuthHeader()">📋 Copy Authorization Header</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div id="decodedTokens" class="step hidden">
|
|
|
|
<h3>🔍 Decoded Token Information</h3>
|
|
|
|
<div class="token-display" id="decodedDisplay"></div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div id="globalStatus" class="status info hidden">
|
|
|
|
<span id="globalStatusText"></span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
// Okta Configuration (will be populated from user input)
|
|
|
|
let oktaConfig = {
|
|
|
|
domain: '',
|
|
|
|
clientId: '',
|
|
|
|
redirectUri: '',
|
|
|
|
baseUrl: '',
|
|
|
|
authServerId: '',
|
|
|
|
authEndpoint: '',
|
|
|
|
tokenEndpoint: '',
|
|
|
|
authApiEndpoint: ''
|
|
|
|
};
|
|
|
|
|
|
|
|
// Global state
|
|
|
|
let currentStep = 0;
|
|
|
|
let sessionToken = null;
|
|
|
|
let pkceParams = {};
|
|
|
|
let tokens = { accessToken: null, idToken: null };
|
|
|
|
let iframeMonitorInterval = null;
|
|
|
|
|
|
|
|
// Step 0: Configuration Management
|
|
|
|
function updateEndpointDisplays() {
|
|
|
|
const domain = document.getElementById('oktaDomain').value;
|
|
|
|
const authServerId = document.getElementById('authServerId').value;
|
|
|
|
|
|
|
|
const baseUrl = `https://${domain}`;
|
|
|
|
const authEndpoint = `${baseUrl}/oauth2/${authServerId}/v1/authorize`;
|
|
|
|
const tokenEndpoint = `${baseUrl}/oauth2/${authServerId}/v1/token`;
|
|
|
|
const authApiEndpoint = `${baseUrl}/api/v1/authn`;
|
|
|
|
|
|
|
|
document.getElementById('displayBaseUrl').textContent = baseUrl;
|
|
|
|
document.getElementById('displayAuthEndpoint').textContent = authEndpoint;
|
|
|
|
document.getElementById('displayTokenEndpoint').textContent = tokenEndpoint;
|
|
|
|
document.getElementById('displayAuthApi').textContent = authApiEndpoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadPresetConfig(preset) {
|
|
|
|
if (preset === 'demo') {
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
document.getElementById('oktaDomain').value = '<YOUR_OKTA_DOMAIN>';
|
|
|
|
document.getElementById('clientId').value = '<YOUR_OKTA_CLIENT_ID>';
|
|
|
|
document.getElementById('redirectUri').value = '<YOUR_REDIRECT_URI>';
|
2025-07-16 14:07:30 -04:00
|
|
|
document.getElementById('authServerId').value = 'default';
|
|
|
|
} else if (preset === 'production') {
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
document.getElementById('oktaDomain').value = '<YOUR_PRODUCTION_OKTA_DOMAIN>';
|
|
|
|
document.getElementById('clientId').value = '<YOUR_PRODUCTION_CLIENT_ID>';
|
|
|
|
document.getElementById('redirectUri').value = '<YOUR_PRODUCTION_REDIRECT_URI>';
|
2025-07-16 14:07:30 -04:00
|
|
|
document.getElementById('authServerId').value = 'default';
|
|
|
|
}
|
|
|
|
updateEndpointDisplays();
|
|
|
|
showGlobalStatus(`✅ ${preset} configuration template loaded`, 'success');
|
|
|
|
}
|
|
|
|
|
|
|
|
async function validateAndSaveConfig() {
|
|
|
|
const domain = document.getElementById('oktaDomain').value.trim();
|
|
|
|
const clientId = document.getElementById('clientId').value.trim();
|
|
|
|
const redirectUri = document.getElementById('redirectUri').value.trim();
|
|
|
|
const authServerId = document.getElementById('authServerId').value.trim();
|
|
|
|
|
|
|
|
// Validation
|
|
|
|
if (!domain || !clientId || !redirectUri || !authServerId) {
|
|
|
|
showGlobalStatus('Please fill in all configuration fields', 'error');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validate domain format
|
|
|
|
if (!domain.includes('.') || domain.startsWith('http')) {
|
|
|
|
showGlobalStatus('Domain should be just the hostname (e.g., dev-12345678.okta.com)', 'error');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validate redirect URI format
|
|
|
|
try {
|
|
|
|
new URL(redirectUri);
|
|
|
|
} catch (e) {
|
|
|
|
showGlobalStatus('Redirect URI must be a valid URL', 'error');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
setConfigLoading(true);
|
|
|
|
showGlobalStatus('Validating Okta configuration...', 'info');
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Build configuration
|
|
|
|
oktaConfig = {
|
|
|
|
domain: domain,
|
|
|
|
clientId: clientId,
|
|
|
|
redirectUri: redirectUri,
|
|
|
|
baseUrl: `https://${domain}`,
|
|
|
|
authServerId: authServerId,
|
|
|
|
authEndpoint: `https://${domain}/oauth2/${authServerId}/v1/authorize`,
|
|
|
|
tokenEndpoint: `https://${domain}/oauth2/${authServerId}/v1/token`,
|
|
|
|
authApiEndpoint: `https://${domain}/api/v1/authn`
|
|
|
|
};
|
|
|
|
|
|
|
|
// Test connectivity to Okta (optional - just check if domain resolves)
|
|
|
|
const testResponse = await fetch(`${oktaConfig.baseUrl}/.well-known/openid_configuration`, {
|
|
|
|
method: 'GET',
|
|
|
|
mode: 'cors'
|
|
|
|
}).catch(() => null);
|
|
|
|
|
|
|
|
if (testResponse && testResponse.ok) {
|
|
|
|
const wellKnown = await testResponse.json();
|
|
|
|
showGlobalStatus('✅ Okta configuration validated successfully!', 'success');
|
|
|
|
|
|
|
|
// Optionally verify endpoints match
|
|
|
|
if (wellKnown.authorization_endpoint !== oktaConfig.authEndpoint) {
|
|
|
|
showGlobalStatus(`⚠️ Warning: Authorization endpoint mismatch. Expected: ${wellKnown.authorization_endpoint}`, 'info');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
showGlobalStatus('⚠️ Could not validate Okta endpoints, but configuration saved', 'info');
|
|
|
|
}
|
|
|
|
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
// Save configuration to localStorage
|
|
|
|
saveConfigToStorage();
|
|
|
|
|
2025-07-16 14:07:30 -04:00
|
|
|
// Move to next step
|
|
|
|
updateProgress(1);
|
|
|
|
showStep(1);
|
|
|
|
showGlobalStatus('Configuration saved! Ready to login.', 'success');
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
showGlobalStatus(`Configuration validation error: ${error.message}`, 'error');
|
|
|
|
} finally {
|
|
|
|
setConfigLoading(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function setConfigLoading(loading) {
|
|
|
|
const spinner = document.getElementById('configSpinner');
|
|
|
|
const text = document.getElementById('configText');
|
|
|
|
const button = document.querySelector('#step0 button');
|
|
|
|
|
|
|
|
if (loading) {
|
|
|
|
spinner.classList.remove('hidden');
|
|
|
|
text.textContent = 'Validating...';
|
|
|
|
button.disabled = true;
|
|
|
|
} else {
|
|
|
|
spinner.classList.add('hidden');
|
|
|
|
text.textContent = '✅ Validate & Save Configuration';
|
|
|
|
button.disabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
// Configuration persistence functions
|
|
|
|
function saveConfigToStorage() {
|
|
|
|
const config = {
|
|
|
|
oktaDomain: document.getElementById('oktaDomain').value,
|
|
|
|
clientId: document.getElementById('clientId').value,
|
|
|
|
redirectUri: document.getElementById('redirectUri').value,
|
|
|
|
authServerId: document.getElementById('authServerId').value
|
|
|
|
};
|
|
|
|
localStorage.setItem('oktaConfig', JSON.stringify(config));
|
|
|
|
showGlobalStatus('✅ Configuration saved locally', 'success');
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadConfigFromStorage() {
|
|
|
|
const saved = localStorage.getItem('oktaConfig');
|
|
|
|
if (saved) {
|
|
|
|
try {
|
|
|
|
const config = JSON.parse(saved);
|
|
|
|
document.getElementById('oktaDomain').value = config.oktaDomain || '<YOUR_OKTA_DOMAIN>';
|
|
|
|
document.getElementById('clientId').value = config.clientId || '<YOUR_OKTA_CLIENT_ID>';
|
|
|
|
document.getElementById('redirectUri').value = config.redirectUri || '<YOUR_REDIRECT_URI>';
|
|
|
|
document.getElementById('authServerId').value = config.authServerId || 'default';
|
|
|
|
updateEndpointDisplays();
|
|
|
|
showGlobalStatus('✅ Configuration loaded from previous session', 'info');
|
|
|
|
return true;
|
|
|
|
} catch (e) {
|
|
|
|
console.warn('Could not load saved config:', e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function clearConfigFromStorage() {
|
|
|
|
localStorage.removeItem('oktaConfig');
|
|
|
|
showGlobalStatus('🗑️ Saved configuration cleared', 'info');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Navigation function
|
|
|
|
function goToStep(stepNumber) {
|
|
|
|
if (stepNumber === 0) {
|
|
|
|
// Always allow going back to config
|
|
|
|
showStep(0);
|
|
|
|
updateProgress(0);
|
|
|
|
showGlobalStatus('📝 Back to configuration', 'info');
|
|
|
|
} else if (stepNumber === 1) {
|
|
|
|
// Only allow going to login if config is valid
|
|
|
|
if (oktaConfig.domain && oktaConfig.clientId) {
|
|
|
|
showStep(1);
|
|
|
|
updateProgress(1);
|
|
|
|
showGlobalStatus('🔐 Ready to login', 'info');
|
|
|
|
} else {
|
|
|
|
showGlobalStatus('⚠️ Please configure Okta settings first', 'error');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Other steps are not directly clickable as they require completing previous steps
|
|
|
|
}
|
|
|
|
|
2025-07-16 14:07:30 -04:00
|
|
|
// Add event listeners for real-time endpoint updates
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
const domainInput = document.getElementById('oktaDomain');
|
|
|
|
const authServerInput = document.getElementById('authServerId');
|
|
|
|
|
|
|
|
domainInput.addEventListener('input', updateEndpointDisplays);
|
|
|
|
authServerInput.addEventListener('input', updateEndpointDisplays);
|
|
|
|
|
fix (02-use-cases): AWS Operations Agent updated with AgentCore Runtime (#177)
* feat: Add AWS Operations Agent with AgentCore Runtime
- Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore
- Added comprehensive deployment scripts for DIY and SDK runtime modes
- Implemented OAuth2/PKCE authentication with Okta integration
- Added MCP (Model Context Protocol) tool support for AWS service operations
- Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders
- Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker
- Includes chatbot client, gateway management scripts, and comprehensive testing
- Ready for public GitHub with security-cleared configuration files
Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders
* Update AWS Operations Agent architecture diagram
---------
Co-authored-by: name <alias@amazon.com>
2025-07-31 11:59:30 -07:00
|
|
|
// Load saved configuration on page load
|
|
|
|
loadConfigFromStorage();
|
|
|
|
|
2025-07-16 14:07:30 -04:00
|
|
|
// Initialize displays
|
|
|
|
updateEndpointDisplays();
|
|
|
|
});
|
|
|
|
|
|
|
|
// Step 1: Perform Login
|
|
|
|
async function performLogin() {
|
|
|
|
const username = document.getElementById('username').value;
|
|
|
|
const password = document.getElementById('password').value;
|
|
|
|
|
|
|
|
if (!username || !password) {
|
|
|
|
showGlobalStatus('Please enter both username and password', 'error');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
setLoginLoading(true);
|
|
|
|
showGlobalStatus('Authenticating with Okta...', 'info');
|
|
|
|
|
|
|
|
try {
|
|
|
|
const authUrl = oktaConfig.authApiEndpoint;
|
|
|
|
|
|
|
|
const response = await fetch(authUrl, {
|
|
|
|
method: 'POST',
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
'Accept': 'application/json'
|
|
|
|
},
|
|
|
|
body: JSON.stringify({
|
|
|
|
username: username,
|
|
|
|
password: password,
|
|
|
|
options: {
|
|
|
|
multiOptionalFactorEnroll: false,
|
|
|
|
warnBeforePasswordExpired: false
|
|
|
|
}
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
const errorData = await response.json();
|
|
|
|
throw new Error(errorData.errorSummary || `HTTP ${response.status}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
const data = await response.json();
|
|
|
|
|
|
|
|
if (data.status === 'SUCCESS') {
|
|
|
|
sessionToken = data.sessionToken;
|
|
|
|
showStep2Success();
|
|
|
|
} else {
|
|
|
|
throw new Error(`Authentication failed: ${data.status}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
showGlobalStatus(`Login failed: ${error.message}`, 'error');
|
|
|
|
} finally {
|
|
|
|
setLoginLoading(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Step 2: Show session token success
|
|
|
|
function showStep2Success() {
|
|
|
|
updateProgress(2);
|
|
|
|
document.getElementById('sessionTokenDisplay').textContent = sessionToken;
|
|
|
|
showStep(2);
|
|
|
|
showGlobalStatus('✅ Login successful! Session token retrieved.', 'success');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Step 3: Start iframe PKCE Flow
|
|
|
|
async function startIframePKCE() {
|
|
|
|
updateProgress(3);
|
|
|
|
showStep(3);
|
|
|
|
showGlobalStatus('Starting iframe PKCE authorization flow...', 'info');
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Generate PKCE parameters
|
|
|
|
pkceParams.codeVerifier = generateCodeVerifier();
|
|
|
|
pkceParams.codeChallenge = await generateCodeChallenge(pkceParams.codeVerifier);
|
|
|
|
pkceParams.state = generateRandomString();
|
|
|
|
pkceParams.nonce = generateRandomString();
|
|
|
|
|
|
|
|
// Build authorization URL
|
|
|
|
const authUrl = new URL(oktaConfig.authEndpoint);
|
|
|
|
const params = {
|
|
|
|
'client_id': oktaConfig.clientId,
|
|
|
|
'response_type': 'code',
|
|
|
|
'scope': 'openid profile email',
|
|
|
|
'redirect_uri': oktaConfig.redirectUri,
|
|
|
|
'state': pkceParams.state,
|
|
|
|
'nonce': pkceParams.nonce,
|
|
|
|
'code_challenge': pkceParams.codeChallenge,
|
|
|
|
'code_challenge_method': 'S256',
|
|
|
|
'sessionToken': sessionToken
|
|
|
|
};
|
|
|
|
|
|
|
|
Object.keys(params).forEach(key => {
|
|
|
|
authUrl.searchParams.append(key, params[key]);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Show iframe container
|
|
|
|
document.getElementById('iframeContainer').classList.remove('hidden');
|
|
|
|
|
|
|
|
// Load authorization URL in iframe
|
|
|
|
const iframe = document.getElementById('oauthIframe');
|
|
|
|
iframe.src = authUrl.toString();
|
|
|
|
|
|
|
|
// Update status
|
|
|
|
document.getElementById('iframeStatus').innerHTML = `
|
|
|
|
<span class="spinner"></span>
|
|
|
|
<span>Loading OAuth authorization in iframe...</span>
|
|
|
|
`;
|
|
|
|
|
|
|
|
// Start monitoring iframe for callback
|
|
|
|
startIframeMonitoring();
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
showGlobalStatus(`iframe PKCE flow error: ${error.message}`, 'error');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Monitor iframe for OAuth callback
|
|
|
|
function startIframeMonitoring() {
|
|
|
|
const iframe = document.getElementById('oauthIframe');
|
|
|
|
let attempts = 0;
|
|
|
|
const maxAttempts = 60; // 60 seconds timeout
|
|
|
|
|
|
|
|
iframeMonitorInterval = setInterval(() => {
|
|
|
|
attempts++;
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Try to access iframe URL
|
|
|
|
const iframeUrl = iframe.contentWindow.location.href;
|
|
|
|
|
|
|
|
// Check if we got redirected to callback with code
|
|
|
|
if (iframeUrl.includes('code=')) {
|
|
|
|
clearInterval(iframeMonitorInterval);
|
|
|
|
|
|
|
|
const urlParams = new URLSearchParams(iframeUrl.split('?')[1]);
|
|
|
|
const code = urlParams.get('code');
|
|
|
|
const state = urlParams.get('state');
|
|
|
|
|
|
|
|
if (code && state === pkceParams.state) {
|
|
|
|
document.getElementById('iframeStatus').innerHTML = `
|
|
|
|
<div class="status success">✅ Authorization code captured from iframe!</div>
|
|
|
|
`;
|
|
|
|
exchangeTokens(code, pkceParams.codeVerifier);
|
|
|
|
} else {
|
|
|
|
throw new Error('Invalid authorization response');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (e) {
|
|
|
|
// Cross-origin error is expected while iframe is on Okta domain
|
|
|
|
// We'll continue monitoring
|
|
|
|
}
|
|
|
|
|
|
|
|
// Timeout after maxAttempts
|
|
|
|
if (attempts >= maxAttempts) {
|
|
|
|
clearInterval(iframeMonitorInterval);
|
|
|
|
document.getElementById('iframeStatus').innerHTML = `
|
|
|
|
<div class="status error">⏰ Timeout waiting for authorization. Please try again.</div>
|
|
|
|
`;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update status every 5 seconds
|
|
|
|
if (attempts % 5 === 0) {
|
|
|
|
document.getElementById('iframeStatus').innerHTML = `
|
|
|
|
<span class="spinner"></span>
|
|
|
|
<span>Waiting for OAuth authorization... (${attempts}s)</span>
|
|
|
|
`;
|
|
|
|
}
|
|
|
|
|
|
|
|
}, 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Exchange tokens
|
|
|
|
async function exchangeTokens(code, codeVerifier) {
|
|
|
|
try {
|
|
|
|
updateProgress(4);
|
|
|
|
showGlobalStatus('Exchanging authorization code for tokens...', 'info');
|
|
|
|
|
|
|
|
const tokenResponse = await fetch(oktaConfig.tokenEndpoint, {
|
|
|
|
method: 'POST',
|
|
|
|
headers: {
|
|
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
|
|
'Accept': 'application/json'
|
|
|
|
},
|
|
|
|
body: new URLSearchParams({
|
|
|
|
'grant_type': 'authorization_code',
|
|
|
|
'client_id': oktaConfig.clientId,
|
|
|
|
'code': code,
|
|
|
|
'redirect_uri': oktaConfig.redirectUri,
|
|
|
|
'code_verifier': codeVerifier
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!tokenResponse.ok) {
|
|
|
|
const errorText = await tokenResponse.text();
|
|
|
|
throw new Error(`Token exchange failed: ${tokenResponse.status} - ${errorText}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
const tokenData = await tokenResponse.json();
|
|
|
|
tokens.accessToken = tokenData.access_token;
|
|
|
|
tokens.idToken = tokenData.id_token;
|
|
|
|
|
|
|
|
showFinalResults();
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
showGlobalStatus(`Token exchange error: ${error.message}`, 'error');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Show final results
|
|
|
|
function showFinalResults() {
|
|
|
|
updateProgress(4, true);
|
|
|
|
showStep('finalResults');
|
|
|
|
|
|
|
|
document.getElementById('finalAccessToken').textContent = tokens.accessToken;
|
|
|
|
document.getElementById('finalIdToken').textContent = tokens.idToken;
|
|
|
|
document.getElementById('tokenForHeader').textContent = tokens.accessToken;
|
|
|
|
|
|
|
|
showGlobalStatus('🎉 PKCE OpenID flow completed successfully!', 'success');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Utility functions
|
|
|
|
function updateProgress(step, completed = false) {
|
|
|
|
for (let i = 0; i <= 4; i++) {
|
|
|
|
const elem = document.getElementById(`step${i}-progress`);
|
|
|
|
if (elem) {
|
|
|
|
elem.classList.remove('active', 'completed');
|
|
|
|
if (i < step || (i === step && completed)) {
|
|
|
|
elem.classList.add('completed');
|
|
|
|
} else if (i === step) {
|
|
|
|
elem.classList.add('active');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
currentStep = step;
|
|
|
|
}
|
|
|
|
|
|
|
|
function showStep(stepId) {
|
|
|
|
document.querySelectorAll('.step').forEach(step => {
|
|
|
|
step.classList.remove('active');
|
|
|
|
step.classList.add('hidden');
|
|
|
|
});
|
|
|
|
|
|
|
|
const targetStep = typeof stepId === 'string' ?
|
|
|
|
document.getElementById(stepId) :
|
|
|
|
document.getElementById(`step${stepId}`);
|
|
|
|
|
|
|
|
if (targetStep) {
|
|
|
|
targetStep.classList.remove('hidden');
|
|
|
|
targetStep.classList.add('active');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function setLoginLoading(loading) {
|
|
|
|
const spinner = document.getElementById('loginSpinner');
|
|
|
|
const text = document.getElementById('loginText');
|
|
|
|
const button = document.querySelector('#step1 button');
|
|
|
|
|
|
|
|
if (loading) {
|
|
|
|
spinner.classList.remove('hidden');
|
|
|
|
text.textContent = 'Authenticating...';
|
|
|
|
button.disabled = true;
|
|
|
|
} else {
|
|
|
|
spinner.classList.add('hidden');
|
|
|
|
text.textContent = '🚀 Login to Okta';
|
|
|
|
button.disabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function showGlobalStatus(message, type) {
|
|
|
|
const statusDiv = document.getElementById('globalStatus');
|
|
|
|
const statusText = document.getElementById('globalStatusText');
|
|
|
|
|
|
|
|
statusText.textContent = message;
|
|
|
|
statusDiv.className = `status ${type}`;
|
|
|
|
statusDiv.classList.remove('hidden');
|
|
|
|
|
|
|
|
if (type === 'success') {
|
|
|
|
setTimeout(() => {
|
|
|
|
statusDiv.classList.add('hidden');
|
|
|
|
}, 5000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function copyToken(type) {
|
|
|
|
const token = type === 'access' ? tokens.accessToken : tokens.idToken;
|
|
|
|
if (!token) return;
|
|
|
|
|
|
|
|
navigator.clipboard.writeText(token).then(() => {
|
|
|
|
showGlobalStatus(`${type} token copied to clipboard!`, 'success');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function copyAuthHeader() {
|
|
|
|
const header = `Authorization: Bearer ${tokens.accessToken}`;
|
|
|
|
navigator.clipboard.writeText(header).then(() => {
|
|
|
|
showGlobalStatus('Authorization header copied to clipboard!', 'success');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function decodeToken(type) {
|
|
|
|
console.log('decodeToken called with type:', type);
|
|
|
|
console.log('Current tokens:', tokens);
|
|
|
|
|
|
|
|
const token = type === 'access' ? tokens.accessToken : tokens.idToken;
|
|
|
|
|
|
|
|
if (!token) {
|
|
|
|
showGlobalStatus(`No ${type} token available to decode`, 'error');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
console.log('Attempting to decode token:', token.substring(0, 50) + '...');
|
|
|
|
|
|
|
|
const parts = token.split('.');
|
|
|
|
if (parts.length !== 3) {
|
|
|
|
throw new Error('Invalid JWT format - token must have 3 parts');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decode header and payload
|
|
|
|
const header = JSON.parse(atob(parts[0]));
|
|
|
|
const payload = JSON.parse(atob(parts[1]));
|
|
|
|
|
|
|
|
console.log('Decoded header:', header);
|
|
|
|
console.log('Decoded payload:', payload);
|
|
|
|
|
|
|
|
const decoded = {
|
|
|
|
tokenType: type.toUpperCase() + ' TOKEN',
|
|
|
|
header: header,
|
|
|
|
payload: payload,
|
|
|
|
claims: {
|
|
|
|
issuer: payload.iss,
|
|
|
|
audience: payload.aud,
|
|
|
|
subject: payload.sub,
|
|
|
|
clientId: payload.cid,
|
|
|
|
scopes: payload.scp,
|
|
|
|
issued: new Date(payload.iat * 1000).toLocaleString(),
|
|
|
|
expires: new Date(payload.exp * 1000).toLocaleString(),
|
|
|
|
authTime: payload.auth_time ? new Date(payload.auth_time * 1000).toLocaleString() : 'N/A'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Add ID token specific claims
|
|
|
|
if (type === 'id') {
|
|
|
|
decoded.claims.name = payload.name || 'N/A';
|
|
|
|
decoded.claims.email = payload.email || 'N/A';
|
|
|
|
decoded.claims.preferredUsername = payload.preferred_username || 'N/A';
|
|
|
|
}
|
|
|
|
|
|
|
|
document.getElementById('decodedDisplay').textContent = JSON.stringify(decoded, null, 2);
|
|
|
|
document.getElementById('decodedTokens').classList.remove('hidden');
|
|
|
|
|
|
|
|
showGlobalStatus(`✅ ${type.toUpperCase()} token decoded successfully!`, 'success');
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Token decode error:', error);
|
|
|
|
showGlobalStatus(`Error decoding ${type} token: ${error.message}`, 'error');
|
|
|
|
|
|
|
|
// Show raw token for debugging
|
|
|
|
document.getElementById('decodedDisplay').textContent = `
|
|
|
|
ERROR DECODING TOKEN:
|
|
|
|
${error.message}
|
|
|
|
|
|
|
|
RAW TOKEN:
|
|
|
|
${token}
|
|
|
|
|
|
|
|
TOKEN PARTS:
|
|
|
|
${token.split('.').map((part, i) => `Part ${i + 1}: ${part}`).join('\n')}
|
|
|
|
`;
|
|
|
|
document.getElementById('decodedTokens').classList.remove('hidden');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// PKCE utility functions
|
|
|
|
function generateCodeVerifier() {
|
|
|
|
const array = new Uint8Array(32);
|
|
|
|
crypto.getRandomValues(array);
|
|
|
|
return base64URLEncode(array);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function generateCodeChallenge(verifier) {
|
|
|
|
const encoder = new TextEncoder();
|
|
|
|
const data = encoder.encode(verifier);
|
|
|
|
const digest = await crypto.subtle.digest('SHA-256', data);
|
|
|
|
return base64URLEncode(new Uint8Array(digest));
|
|
|
|
}
|
|
|
|
|
|
|
|
function base64URLEncode(array) {
|
|
|
|
return btoa(String.fromCharCode.apply(null, array))
|
|
|
|
.replace(/\+/g, '-')
|
|
|
|
.replace(/\//g, '_')
|
|
|
|
.replace(/=/g, '');
|
|
|
|
}
|
|
|
|
|
|
|
|
function generateRandomString() {
|
|
|
|
const array = new Uint8Array(16);
|
|
|
|
crypto.getRandomValues(array);
|
|
|
|
return base64URLEncode(array);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cleanup on page unload
|
|
|
|
window.addEventListener('beforeunload', function() {
|
|
|
|
if (iframeMonitorInterval) {
|
|
|
|
clearInterval(iframeMonitorInterval);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|