Files
OmniRoute/src/shared/components/KiroOAuthWrapper.tsx
Thiago Reis 3a28b3b5e8 feat: add Kiro API key authentication (#6587)
* feat(oauth): add Kiro long-lived API key auth (#6587)

New /api/oauth/kiro/api-key route + KiroService.validateApiKey let a
Kiro account be linked with a long-lived AWS CodeWhisperer/Kiro API
key instead of the interactive OAuth device flow, with live
per-account model discovery (ListAvailableModels, 5-minute cache)
layered over the existing static registry fallback.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(changelog): re-restore #6587 bullet after release sync

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(merge): restore #6126 clinepass files reverted by release auto-resolve + baseline re-merge

The release sync's auto-resolve reverted sibling PR #6126's clinepass work
(registry, catalog, oauth constants, clineAuth.ts, token-refresh case, tests)
and the file-size baseline — all outside this PR's scope. Restored to the
release versions, re-applied only this PR's own baseline entries, restored the
#6126 CHANGELOG bullet (re-inserting only this PR's own).

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* chore(quality): freeze public-creds FP — AWS region default in validateApiKey signature

Same class as the existing minimax fn-param FPs: CRED_KEY_RE matches the
apiKey: param annotation and captures the region default "us-east-1",
which is not a credential.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(kiro): keep hard-failure reject semantics + kill public-creds fn-param FP at the source

- getKiroUsage: exhausted non-auth attempts now REJECT with the last HTTP-status
  failure in the pre-#6587 format (usage-service-hardening relies on it); auth
  failures keep the soft social-auth message.
- validateApiKey: region default moved out of the parameter list (the
  check-public-creds CRED_KEY_RE matches the apiKey: annotation and flags any
  literal in the signature); drops the brittle line-keyed allowlist entry.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: strangersp <strangersp@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
2026-07-09 22:49:06 -03:00

120 lines
3.1 KiB
TypeScript

"use client";
import { useState, useCallback } from "react";
import OAuthModal from "./OAuthModal";
import KiroAuthModal from "./KiroAuthModal";
import KiroSocialOAuthModal from "./KiroSocialOAuthModal";
type KiroOAuthWrapperProps = {
isOpen: boolean;
providerInfo?: { id?: string; name?: string } | null;
onSuccess?: () => void;
onClose: () => void;
reauthConnection?: null | { id?: string };
};
/**
* Kiro OAuth Wrapper
* Orchestrates between method selection, device code flow, and social login flow
*/
export default function KiroOAuthWrapper({
isOpen,
providerInfo,
onSuccess,
onClose,
reauthConnection,
}: KiroOAuthWrapperProps) {
const [authMethod, setAuthMethod] = useState(null); // null | "builder-id" | "idc" | "social" | "import" | "api-key"
const [socialProvider, setSocialProvider] = useState(null); // "google" | "github"
const [idcConfig, setIdcConfig] = useState(null);
const handleMethodSelect = useCallback(
(method, config) => {
if (method === "builder-id") {
// Use device code flow (AWS Builder ID)
setAuthMethod("builder-id");
} else if (method === "idc") {
// Use device code flow with IDC config
setAuthMethod("idc");
setIdcConfig(config);
} else if (method === "social") {
// Use social login with manual callback
setAuthMethod("social");
setSocialProvider(config.provider);
} else if (method === "import") {
// Import handled in KiroAuthModal, just close
onSuccess?.();
} else if (method === "api-key") {
// API-key import is handled in KiroAuthModal.
onSuccess?.();
}
},
[onSuccess]
);
const handleBack = () => {
setAuthMethod(null);
setSocialProvider(null);
setIdcConfig(null);
};
const handleSocialSuccess = () => {
setAuthMethod(null);
setSocialProvider(null);
onSuccess?.();
};
const handleDeviceSuccess = () => {
setAuthMethod(null);
setIdcConfig(null);
onSuccess?.();
};
// Show method selection first
const oauthProviderId = providerInfo?.id || "kiro";
const providerLabel = providerInfo?.name || "Kiro";
if (!authMethod) {
return (
<KiroAuthModal
isOpen={isOpen}
providerId={oauthProviderId}
providerLabel={providerLabel}
onMethodSelect={handleMethodSelect}
onClose={onClose}
/>
);
}
// Show device code flow (Builder ID or IDC)
if (authMethod === "builder-id" || authMethod === "idc") {
return (
<OAuthModal
isOpen={isOpen}
provider={oauthProviderId}
providerInfo={providerInfo}
onSuccess={handleDeviceSuccess}
reauthConnection={reauthConnection}
onClose={handleBack}
idcConfig={idcConfig}
/>
);
}
// Show social login flow (Google/GitHub with manual callback)
if (authMethod === "social" && socialProvider) {
return (
<KiroSocialOAuthModal
isOpen={isOpen}
provider={socialProvider}
targetProvider={oauthProviderId}
providerLabel={providerLabel}
onSuccess={handleSocialSuccess}
onClose={handleBack}
/>
);
}
return null;
}