feat: Passwordless cross-device authentication

- Arkitektur: docs/auth/passwordless-architecture.md
- Backend: iom/quixzoom-auth-service/ (FastAPI + Redis)
- Webb: quixzoom-market-pages/se/login/ (QR-kod + polling)
- App: iom/quixzoom-app/src/features/auth/ (push + deep links)

Flöde: QR-kod → app-godkännande → webb-inloggad
This commit is contained in:
Bernt
2026-07-07 07:11:50 +00:00
parent 4aa984ad74
commit 6989a98d75
61843 changed files with 5491611 additions and 872231 deletions
+4
View File
@@ -0,0 +1,4 @@
export type { WorkloadIdentity, SubjectTokenProvider, TokenExchangeResponse } from "./types.mjs";
export { k8sServiceAccountTokenProvider, azureManagedIdentityTokenProvider, gcpIDTokenProvider, } from "./subject-token-providers.mjs";
export { OAuthError, SubjectTokenProviderError } from "../core/error.mjs";
//# sourceMappingURL=index.d.mts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,oBAAgB;AAE7F,OAAO,EACL,8BAA8B,EAC9B,iCAAiC,EACjC,kBAAkB,GACnB,sCAAkC;AAEnC,OAAO,EAAE,UAAU,EAAE,yBAAyB,EAAE,0BAAsB"}
+4
View File
@@ -0,0 +1,4 @@
export type { WorkloadIdentity, SubjectTokenProvider, TokenExchangeResponse } from "./types.js";
export { k8sServiceAccountTokenProvider, azureManagedIdentityTokenProvider, gcpIDTokenProvider, } from "./subject-token-providers.js";
export { OAuthError, SubjectTokenProviderError } from "../core/error.js";
//# sourceMappingURL=index.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,mBAAgB;AAE7F,OAAO,EACL,8BAA8B,EAC9B,iCAAiC,EACjC,kBAAkB,GACnB,qCAAkC;AAEnC,OAAO,EAAE,UAAU,EAAE,yBAAyB,EAAE,yBAAsB"}
+11
View File
@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SubjectTokenProviderError = exports.OAuthError = exports.gcpIDTokenProvider = exports.azureManagedIdentityTokenProvider = exports.k8sServiceAccountTokenProvider = void 0;
var subject_token_providers_1 = require("./subject-token-providers.js");
Object.defineProperty(exports, "k8sServiceAccountTokenProvider", { enumerable: true, get: function () { return subject_token_providers_1.k8sServiceAccountTokenProvider; } });
Object.defineProperty(exports, "azureManagedIdentityTokenProvider", { enumerable: true, get: function () { return subject_token_providers_1.azureManagedIdentityTokenProvider; } });
Object.defineProperty(exports, "gcpIDTokenProvider", { enumerable: true, get: function () { return subject_token_providers_1.gcpIDTokenProvider; } });
var error_1 = require("../core/error.js");
Object.defineProperty(exports, "OAuthError", { enumerable: true, get: function () { return error_1.OAuthError; } });
Object.defineProperty(exports, "SubjectTokenProviderError", { enumerable: true, get: function () { return error_1.SubjectTokenProviderError; } });
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/auth/index.ts"],"names":[],"mappings":";;;AAEA,wEAImC;AAHjC,yIAAA,8BAA8B,OAAA;AAC9B,4IAAA,iCAAiC,OAAA;AACjC,6HAAA,kBAAkB,OAAA;AAGpB,0CAAsE;AAA7D,mGAAA,UAAU,OAAA;AAAE,kHAAA,yBAAyB,OAAA"}
+3
View File
@@ -0,0 +1,3 @@
export { k8sServiceAccountTokenProvider, azureManagedIdentityTokenProvider, gcpIDTokenProvider, } from "./subject-token-providers.mjs";
export { OAuthError, SubjectTokenProviderError } from "../core/error.mjs";
//# sourceMappingURL=index.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/auth/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,8BAA8B,EAC9B,iCAAiC,EACjC,kBAAkB,GACnB,sCAAkC;AAEnC,OAAO,EAAE,UAAU,EAAE,yBAAyB,EAAE,0BAAsB"}
+20
View File
@@ -0,0 +1,20 @@
import type { SubjectTokenProvider } from "./types.mjs";
import type { Fetch } from "../internal/builtin-types.mjs";
type ReadFile = (path: string) => Promise<string>;
export declare function k8sServiceAccountTokenProvider(tokenPath?: string, config?: {
readFile?: ReadFile;
}): SubjectTokenProvider;
export declare function azureManagedIdentityTokenProvider(resource?: string, config?: {
objectId?: string;
clientId?: string;
msiResId?: string;
apiVersion?: string;
timeout?: number;
fetch?: Fetch;
}): SubjectTokenProvider;
export declare function gcpIDTokenProvider(audience?: string, config?: {
timeout?: number;
fetch?: Fetch;
}): SubjectTokenProvider;
export {};
//# sourceMappingURL=subject-token-providers.d.mts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"subject-token-providers.d.mts","sourceRoot":"","sources":["../src/auth/subject-token-providers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAgB;AACpD,OAAO,KAAK,EAAE,KAAK,EAAE,sCAAkC;AAQvD,KAAK,QAAQ,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAclD,wBAAgB,8BAA8B,CAC5C,SAAS,GAAE,MAA8D,EACzE,MAAM,CAAC,EAAE;IACP,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,GACA,oBAAoB,CAiCtB;AAED,wBAAgB,iCAAiC,CAC/C,QAAQ,GAAE,MAAyB,EACnC,MAAM,CAAC,EAAE;IACP,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,GACA,oBAAoB,CA4DtB;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,GAAE,MAAoC,EAC9C,MAAM,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAC3C,oBAAoB,CA8CtB"}
+20
View File
@@ -0,0 +1,20 @@
import type { SubjectTokenProvider } from "./types.js";
import type { Fetch } from "../internal/builtin-types.js";
type ReadFile = (path: string) => Promise<string>;
export declare function k8sServiceAccountTokenProvider(tokenPath?: string, config?: {
readFile?: ReadFile;
}): SubjectTokenProvider;
export declare function azureManagedIdentityTokenProvider(resource?: string, config?: {
objectId?: string;
clientId?: string;
msiResId?: string;
apiVersion?: string;
timeout?: number;
fetch?: Fetch;
}): SubjectTokenProvider;
export declare function gcpIDTokenProvider(audience?: string, config?: {
timeout?: number;
fetch?: Fetch;
}): SubjectTokenProvider;
export {};
//# sourceMappingURL=subject-token-providers.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"subject-token-providers.d.ts","sourceRoot":"","sources":["../src/auth/subject-token-providers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAgB;AACpD,OAAO,KAAK,EAAE,KAAK,EAAE,qCAAkC;AAQvD,KAAK,QAAQ,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAclD,wBAAgB,8BAA8B,CAC5C,SAAS,GAAE,MAA8D,EACzE,MAAM,CAAC,EAAE;IACP,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,GACA,oBAAoB,CAiCtB;AAED,wBAAgB,iCAAiC,CAC/C,QAAQ,GAAE,MAAyB,EACnC,MAAM,CAAC,EAAE;IACP,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,GACA,oBAAoB,CA4DtB;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,GAAE,MAAoC,EAC9C,MAAM,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAC3C,oBAAoB,CA8CtB"}
+127
View File
@@ -0,0 +1,127 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.k8sServiceAccountTokenProvider = k8sServiceAccountTokenProvider;
exports.azureManagedIdentityTokenProvider = azureManagedIdentityTokenProvider;
exports.gcpIDTokenProvider = gcpIDTokenProvider;
const tslib_1 = require("../internal/tslib.js");
const Shims = tslib_1.__importStar(require("../internal/shims.js"));
const error_1 = require("../core/error.js");
const DEFAULT_RESOURCE = 'https://management.azure.com/';
const DEFAULT_AZURE_API_VERSION = '2018-02-01';
const AZURE_IMDS_BASE_URL = 'http://169.254.169.254/metadata/identity/oauth2/token';
let fsPromisesModule;
async function defaultReadFile(path) {
fsPromisesModule ?? (fsPromisesModule = Promise.resolve().then(() => tslib_1.__importStar(require('fs/promises'))).catch((error) => {
fsPromisesModule = undefined;
throw error;
}));
const { readFile } = await fsPromisesModule;
return readFile(path, 'utf8');
}
function k8sServiceAccountTokenProvider(tokenPath = '/var/run/secrets/kubernetes.io/serviceaccount/token', config) {
const readFile = config?.readFile ?? defaultReadFile;
return {
tokenType: 'jwt',
getToken: async () => {
let rawToken;
try {
rawToken = await readFile(tokenPath);
}
catch (error) {
if (error instanceof error_1.SubjectTokenProviderError) {
throw error;
}
throw new error_1.SubjectTokenProviderError(`Failed to read Kubernetes service account token from ${tokenPath}: ${error instanceof Error ? error.message : String(error)}`, 'kubernetes', error instanceof Error ? error : undefined);
}
const token = rawToken.trim();
if (token.length === 0) {
throw new error_1.SubjectTokenProviderError(`The token file at ${tokenPath} is empty.`, 'kubernetes');
}
return token;
},
};
}
function azureManagedIdentityTokenProvider(resource = DEFAULT_RESOURCE, config) {
const apiVersion = config?.apiVersion ?? DEFAULT_AZURE_API_VERSION;
const timeout = config?.timeout ?? 10000;
return {
tokenType: 'jwt',
getToken: async () => {
const url = new URL(AZURE_IMDS_BASE_URL);
url.searchParams.set('api-version', apiVersion);
url.searchParams.set('resource', resource);
if (config?.objectId) {
url.searchParams.set('object_id', config.objectId);
}
if (config?.clientId) {
url.searchParams.set('client_id', config.clientId);
}
if (config?.msiResId) {
url.searchParams.set('msi_res_id', config.msiResId);
}
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await (config?.fetch ?? Shims.getDefaultFetch())(url.toString(), {
headers: {
Metadata: 'true',
},
signal: controller.signal,
});
if (!response.ok) {
throw new error_1.SubjectTokenProviderError(`Failed to fetch token from Azure IMDS: status ${response.status}`, 'azure-imds');
}
const data = (await response.json());
if (!data.access_token) {
throw new error_1.SubjectTokenProviderError("IMDS response missing 'access_token' field", 'azure-imds');
}
return data.access_token;
}
catch (error) {
if (error instanceof error_1.SubjectTokenProviderError) {
throw error;
}
throw new error_1.SubjectTokenProviderError('failed to fetch token from IMDS', 'azure-imds', error instanceof Error ? error : undefined);
}
finally {
clearTimeout(timeoutId);
}
},
};
}
function gcpIDTokenProvider(audience = 'https://api.openai.com/v1', config) {
const timeout = config?.timeout || 10000;
return {
tokenType: 'id',
getToken: async () => {
const url = new URL(`http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity`);
url.searchParams.set('audience', audience);
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await (config?.fetch ?? Shims.getDefaultFetch())(url.toString(), {
headers: {
'Metadata-Flavor': 'Google',
},
signal: controller.signal,
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`GCP Metadata Server returned ${response.status}: ${errorText}`);
}
const token = (await response.text()).trim();
if (!token) {
throw new Error('GCP metadata server returned an empty token');
}
return token;
}
catch (error) {
throw new error_1.SubjectTokenProviderError(`Failed to fetch token from GCP Metadata Server: ${error instanceof Error ? error.message : String(error)}`, 'gcp-metadata', error instanceof Error ? error : undefined);
}
finally {
clearTimeout(timeoutId);
}
},
};
}
//# sourceMappingURL=subject-token-providers.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"subject-token-providers.js","sourceRoot":"","sources":["../src/auth/subject-token-providers.ts"],"names":[],"mappings":"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"}
+121
View File
@@ -0,0 +1,121 @@
import * as Shims from "../internal/shims.mjs";
import { SubjectTokenProviderError } from "../core/error.mjs";
const DEFAULT_RESOURCE = 'https://management.azure.com/';
const DEFAULT_AZURE_API_VERSION = '2018-02-01';
const AZURE_IMDS_BASE_URL = 'http://169.254.169.254/metadata/identity/oauth2/token';
let fsPromisesModule;
async function defaultReadFile(path) {
fsPromisesModule ?? (fsPromisesModule = import('fs/promises').catch((error) => {
fsPromisesModule = undefined;
throw error;
}));
const { readFile } = await fsPromisesModule;
return readFile(path, 'utf8');
}
export function k8sServiceAccountTokenProvider(tokenPath = '/var/run/secrets/kubernetes.io/serviceaccount/token', config) {
const readFile = config?.readFile ?? defaultReadFile;
return {
tokenType: 'jwt',
getToken: async () => {
let rawToken;
try {
rawToken = await readFile(tokenPath);
}
catch (error) {
if (error instanceof SubjectTokenProviderError) {
throw error;
}
throw new SubjectTokenProviderError(`Failed to read Kubernetes service account token from ${tokenPath}: ${error instanceof Error ? error.message : String(error)}`, 'kubernetes', error instanceof Error ? error : undefined);
}
const token = rawToken.trim();
if (token.length === 0) {
throw new SubjectTokenProviderError(`The token file at ${tokenPath} is empty.`, 'kubernetes');
}
return token;
},
};
}
export function azureManagedIdentityTokenProvider(resource = DEFAULT_RESOURCE, config) {
const apiVersion = config?.apiVersion ?? DEFAULT_AZURE_API_VERSION;
const timeout = config?.timeout ?? 10000;
return {
tokenType: 'jwt',
getToken: async () => {
const url = new URL(AZURE_IMDS_BASE_URL);
url.searchParams.set('api-version', apiVersion);
url.searchParams.set('resource', resource);
if (config?.objectId) {
url.searchParams.set('object_id', config.objectId);
}
if (config?.clientId) {
url.searchParams.set('client_id', config.clientId);
}
if (config?.msiResId) {
url.searchParams.set('msi_res_id', config.msiResId);
}
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await (config?.fetch ?? Shims.getDefaultFetch())(url.toString(), {
headers: {
Metadata: 'true',
},
signal: controller.signal,
});
if (!response.ok) {
throw new SubjectTokenProviderError(`Failed to fetch token from Azure IMDS: status ${response.status}`, 'azure-imds');
}
const data = (await response.json());
if (!data.access_token) {
throw new SubjectTokenProviderError("IMDS response missing 'access_token' field", 'azure-imds');
}
return data.access_token;
}
catch (error) {
if (error instanceof SubjectTokenProviderError) {
throw error;
}
throw new SubjectTokenProviderError('failed to fetch token from IMDS', 'azure-imds', error instanceof Error ? error : undefined);
}
finally {
clearTimeout(timeoutId);
}
},
};
}
export function gcpIDTokenProvider(audience = 'https://api.openai.com/v1', config) {
const timeout = config?.timeout || 10000;
return {
tokenType: 'id',
getToken: async () => {
const url = new URL(`http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity`);
url.searchParams.set('audience', audience);
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await (config?.fetch ?? Shims.getDefaultFetch())(url.toString(), {
headers: {
'Metadata-Flavor': 'Google',
},
signal: controller.signal,
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`GCP Metadata Server returned ${response.status}: ${errorText}`);
}
const token = (await response.text()).trim();
if (!token) {
throw new Error('GCP metadata server returned an empty token');
}
return token;
}
catch (error) {
throw new SubjectTokenProviderError(`Failed to fetch token from GCP Metadata Server: ${error instanceof Error ? error.message : String(error)}`, 'gcp-metadata', error instanceof Error ? error : undefined);
}
finally {
clearTimeout(timeoutId);
}
},
};
}
//# sourceMappingURL=subject-token-providers.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"subject-token-providers.mjs","sourceRoot":"","sources":["../src/auth/subject-token-providers.ts"],"names":[],"mappings":"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"}
+23
View File
@@ -0,0 +1,23 @@
export interface SubjectTokenProvider {
tokenType: 'jwt' | 'id';
getToken: () => Promise<string>;
}
export interface WorkloadIdentity {
/**Optional client identifier for token exchange compatibility.*/
clientId?: string;
/**Identity provider resource id in WIFAPI.*/
identityProviderId: string;
/**OpenAI Service account id to bind the verified external identity to.*/
serviceAccountId: string;
/**The provider configuration for obtaining the subject token.*/
provider: SubjectTokenProvider;
/**Optional buffer time in seconds to refresh the OpenAI token before it expires. Defaults to 1200 seconds (20 minutes).*/
refreshBufferSeconds?: number;
}
export interface TokenExchangeResponse {
access_token: string;
issued_token_type: string;
token_type: string;
expires_in?: number;
}
//# sourceMappingURL=types.d.mts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../src/auth/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,KAAK,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,6CAA6C;IAC7C,kBAAkB,EAAE,MAAM,CAAC;IAE3B,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,CAAC;IAEzB,gEAAgE;IAChE,QAAQ,EAAE,oBAAoB,CAAC;IAE/B,0HAA0H;IAC1H,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
+23
View File
@@ -0,0 +1,23 @@
export interface SubjectTokenProvider {
tokenType: 'jwt' | 'id';
getToken: () => Promise<string>;
}
export interface WorkloadIdentity {
/**Optional client identifier for token exchange compatibility.*/
clientId?: string;
/**Identity provider resource id in WIFAPI.*/
identityProviderId: string;
/**OpenAI Service account id to bind the verified external identity to.*/
serviceAccountId: string;
/**The provider configuration for obtaining the subject token.*/
provider: SubjectTokenProvider;
/**Optional buffer time in seconds to refresh the OpenAI token before it expires. Defaults to 1200 seconds (20 minutes).*/
refreshBufferSeconds?: number;
}
export interface TokenExchangeResponse {
access_token: string;
issued_token_type: string;
token_type: string;
expires_in?: number;
}
//# sourceMappingURL=types.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/auth/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,KAAK,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,6CAA6C;IAC7C,kBAAkB,EAAE,MAAM,CAAC;IAE3B,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,CAAC;IAEzB,gEAAgE;IAChE,QAAQ,EAAE,oBAAoB,CAAC;IAE/B,0HAA0H;IAC1H,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/auth/types.ts"],"names":[],"mappings":""}
+2
View File
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=types.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"types.mjs","sourceRoot":"","sources":["../src/auth/types.ts"],"names":[],"mappings":""}
+16
View File
@@ -0,0 +1,16 @@
import type { WorkloadIdentity } from "./types.mjs";
import type { Fetch } from "../internal/builtin-types.mjs";
export declare class WorkloadIdentityAuth {
private cachedToken;
private refreshPromise;
private readonly config;
private readonly tokenExchangeUrl;
private readonly fetch;
constructor(config: WorkloadIdentity, fetch?: Fetch);
getToken(): Promise<string>;
private refreshToken;
private isTokenExpired;
private needsRefresh;
invalidateToken(): void;
}
//# sourceMappingURL=workload-identity-auth.d.mts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"workload-identity-auth.d.mts","sourceRoot":"","sources":["../src/auth/workload-identity-auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAyB,oBAAgB;AACvE,OAAO,KAAK,EAAE,KAAK,EAAE,sCAAkC;AAgBvD,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAiD;IAClF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;gBAElB,MAAM,EAAE,gBAAgB,EAAE,KAAK,CAAC,EAAE,KAAK;IAK7C,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;YAyBnB,YAAY;IAgE1B,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,YAAY;IAMpB,eAAe,IAAI,IAAI;CAIxB"}
+16
View File
@@ -0,0 +1,16 @@
import type { WorkloadIdentity } from "./types.js";
import type { Fetch } from "../internal/builtin-types.js";
export declare class WorkloadIdentityAuth {
private cachedToken;
private refreshPromise;
private readonly config;
private readonly tokenExchangeUrl;
private readonly fetch;
constructor(config: WorkloadIdentity, fetch?: Fetch);
getToken(): Promise<string>;
private refreshToken;
private isTokenExpired;
private needsRefresh;
invalidateToken(): void;
}
//# sourceMappingURL=workload-identity-auth.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"workload-identity-auth.d.ts","sourceRoot":"","sources":["../src/auth/workload-identity-auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAyB,mBAAgB;AACvE,OAAO,KAAK,EAAE,KAAK,EAAE,qCAAkC;AAgBvD,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAiD;IAClF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;gBAElB,MAAM,EAAE,gBAAgB,EAAE,KAAK,CAAC,EAAE,KAAK;IAK7C,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;YAyBnB,YAAY;IAgE1B,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,YAAY;IAMpB,eAAe,IAAI,IAAI;CAIxB"}
+103
View File
@@ -0,0 +1,103 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WorkloadIdentityAuth = void 0;
const tslib_1 = require("../internal/tslib.js");
const Shims = tslib_1.__importStar(require("../internal/shims.js"));
const error_1 = require("../core/error.js");
const SUBJECT_TOKEN_TYPES = {
jwt: 'urn:ietf:params:oauth:token-type:jwt',
id: 'urn:ietf:params:oauth:token-type:id_token',
};
const TOKEN_EXCHANGE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:token-exchange';
class WorkloadIdentityAuth {
constructor(config, fetch) {
this.cachedToken = null;
this.refreshPromise = null;
this.tokenExchangeUrl = 'https://auth.openai.com/oauth/token';
this.config = config;
this.fetch = fetch ?? Shims.getDefaultFetch();
}
async getToken() {
if (!this.cachedToken || this.isTokenExpired(this.cachedToken)) {
if (this.refreshPromise) {
return await this.refreshPromise;
}
this.refreshPromise = this.refreshToken();
try {
const token = await this.refreshPromise;
return token;
}
finally {
this.refreshPromise = null;
}
}
if (this.needsRefresh(this.cachedToken) && !this.refreshPromise) {
this.refreshPromise = this.refreshToken().finally(() => {
this.refreshPromise = null;
});
}
return this.cachedToken.token;
}
async refreshToken() {
const subjectToken = await this.config.provider.getToken();
const body = {
grant_type: TOKEN_EXCHANGE_GRANT_TYPE,
subject_token: subjectToken,
subject_token_type: SUBJECT_TOKEN_TYPES[this.config.provider.tokenType],
identity_provider_id: this.config.identityProviderId,
service_account_id: this.config.serviceAccountId,
};
if (this.config.clientId) {
body['client_id'] = this.config.clientId;
}
const response = await this.fetch(this.tokenExchangeUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
if (!response.ok) {
const errorText = await response.text();
let body = undefined;
try {
body = JSON.parse(errorText);
}
catch { }
if (response.status === 400 || response.status === 401 || response.status === 403) {
throw new error_1.OAuthError(response.status, body, response.headers);
}
throw error_1.APIError.generate(response.status, body, `Token exchange failed with status ${response.status}`, response.headers);
}
const tokenResponse = await response.json();
if (typeof tokenResponse !== 'object' ||
tokenResponse === null ||
!('access_token' in tokenResponse) ||
typeof tokenResponse.access_token !== 'string' ||
tokenResponse.access_token.trim().length === 0) {
throw new error_1.OpenAIError("Token exchange response missing 'access_token' field");
}
const accessToken = tokenResponse.access_token;
const expiresIn = tokenResponse.expires_in ?? 3600;
const expiresAt = Date.now() + expiresIn * 1000;
this.cachedToken = {
token: accessToken,
expiresAt,
};
return accessToken;
}
isTokenExpired(cachedToken) {
return Date.now() >= cachedToken.expiresAt;
}
needsRefresh(cachedToken) {
const bufferSeconds = this.config.refreshBufferSeconds ?? 1200;
const bufferMs = bufferSeconds * 1000;
return Date.now() >= cachedToken.expiresAt - bufferMs;
}
invalidateToken() {
this.cachedToken = null;
this.refreshPromise = null;
}
}
exports.WorkloadIdentityAuth = WorkloadIdentityAuth;
//# sourceMappingURL=workload-identity-auth.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"workload-identity-auth.js","sourceRoot":"","sources":["../src/auth/workload-identity-auth.ts"],"names":[],"mappings":";;;;AAEA,oEAA2C;AAC3C,4CAAkE;AAOlE,MAAM,mBAAmB,GAA8D;IACrF,GAAG,EAAE,sCAAsC;IAC3C,EAAE,EAAE,2CAA2C;CAChD,CAAC;AAEF,MAAM,yBAAyB,GAAG,iDAAiD,CAAC;AAEpF,MAAa,oBAAoB;IAO/B,YAAY,MAAwB,EAAE,KAAa;QAN3C,gBAAW,GAAuB,IAAI,CAAC;QACvC,mBAAc,GAA2B,IAAI,CAAC;QAErC,qBAAgB,GAAW,qCAAqC,CAAC;QAIhF,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/D,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBACxB,OAAO,MAAM,IAAI,CAAC,cAAc,CAAC;YACnC,CAAC;YAED,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YAE1C,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC;gBACxC,OAAO,KAAK,CAAC;YACf,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;YAC7B,CAAC;QACH,CAAC;QAED,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YAChE,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;gBACrD,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;YAC7B,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;IAChC,CAAC;IAEO,KAAK,CAAC,YAAY;QACxB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAC3D,MAAM,IAAI,GAA2B;YACnC,UAAU,EAAE,yBAAyB;YACrC,aAAa,EAAE,YAAY;YAC3B,kBAAkB,EAAE,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;YACvE,oBAAoB,EAAE,IAAI,CAAC,MAAM,CAAC,kBAAkB;YACpD,kBAAkB,EAAE,IAAI,CAAC,MAAM,CAAC,gBAAgB;SACjD,CAAC;QAEF,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACzB,IAAI,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;QAC3C,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,EAAE;YACvD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,IAAI,IAAI,GAAQ,SAAS,CAAC;YAE1B,IAAI,CAAC;gBACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAC/B,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;YAEV,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAClF,MAAM,IAAI,kBAAU,CAAC,QAAQ,CAAC,MAAyB,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;YACnF,CAAC;YACD,MAAM,gBAAQ,CAAC,QAAQ,CACrB,QAAQ,CAAC,MAAM,EACf,IAAI,EACJ,qCAAqC,QAAQ,CAAC,MAAM,EAAE,EACtD,QAAQ,CAAC,OAAO,CACjB,CAAC;QACJ,CAAC;QAED,MAAM,aAAa,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACrD,IACE,OAAO,aAAa,KAAK,QAAQ;YACjC,aAAa,KAAK,IAAI;YACtB,CAAC,CAAC,cAAc,IAAI,aAAa,CAAC;YAClC,OAAO,aAAa,CAAC,YAAY,KAAK,QAAQ;YAC9C,aAAa,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAC9C,CAAC;YACD,MAAM,IAAI,mBAAW,CAAC,sDAAsD,CAAC,CAAC;QAChF,CAAC;QAED,MAAM,WAAW,GAAG,aAAa,CAAC,YAAY,CAAC;QAC/C,MAAM,SAAS,GAAI,aAAgD,CAAC,UAAU,IAAI,IAAI,CAAC;QACvF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC;QAEhD,IAAI,CAAC,WAAW,GAAG;YACjB,KAAK,EAAE,WAAW;YAClB,SAAS;SACV,CAAC;QAEF,OAAO,WAAW,CAAC;IACrB,CAAC;IAEO,cAAc,CAAC,WAAwB;QAC7C,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,WAAW,CAAC,SAAS,CAAC;IAC7C,CAAC;IAEO,YAAY,CAAC,WAAwB;QAC3C,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,oBAAoB,IAAI,IAAI,CAAC;QAC/D,MAAM,QAAQ,GAAG,aAAa,GAAG,IAAI,CAAC;QACtC,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,WAAW,CAAC,SAAS,GAAG,QAAQ,CAAC;IACxD,CAAC;IAED,eAAe;QACb,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;IAC7B,CAAC;CACF;AAnHD,oDAmHC"}
+98
View File
@@ -0,0 +1,98 @@
import * as Shims from "../internal/shims.mjs";
import { APIError, OAuthError, OpenAIError } from "../core/error.mjs";
const SUBJECT_TOKEN_TYPES = {
jwt: 'urn:ietf:params:oauth:token-type:jwt',
id: 'urn:ietf:params:oauth:token-type:id_token',
};
const TOKEN_EXCHANGE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:token-exchange';
export class WorkloadIdentityAuth {
constructor(config, fetch) {
this.cachedToken = null;
this.refreshPromise = null;
this.tokenExchangeUrl = 'https://auth.openai.com/oauth/token';
this.config = config;
this.fetch = fetch ?? Shims.getDefaultFetch();
}
async getToken() {
if (!this.cachedToken || this.isTokenExpired(this.cachedToken)) {
if (this.refreshPromise) {
return await this.refreshPromise;
}
this.refreshPromise = this.refreshToken();
try {
const token = await this.refreshPromise;
return token;
}
finally {
this.refreshPromise = null;
}
}
if (this.needsRefresh(this.cachedToken) && !this.refreshPromise) {
this.refreshPromise = this.refreshToken().finally(() => {
this.refreshPromise = null;
});
}
return this.cachedToken.token;
}
async refreshToken() {
const subjectToken = await this.config.provider.getToken();
const body = {
grant_type: TOKEN_EXCHANGE_GRANT_TYPE,
subject_token: subjectToken,
subject_token_type: SUBJECT_TOKEN_TYPES[this.config.provider.tokenType],
identity_provider_id: this.config.identityProviderId,
service_account_id: this.config.serviceAccountId,
};
if (this.config.clientId) {
body['client_id'] = this.config.clientId;
}
const response = await this.fetch(this.tokenExchangeUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
if (!response.ok) {
const errorText = await response.text();
let body = undefined;
try {
body = JSON.parse(errorText);
}
catch { }
if (response.status === 400 || response.status === 401 || response.status === 403) {
throw new OAuthError(response.status, body, response.headers);
}
throw APIError.generate(response.status, body, `Token exchange failed with status ${response.status}`, response.headers);
}
const tokenResponse = await response.json();
if (typeof tokenResponse !== 'object' ||
tokenResponse === null ||
!('access_token' in tokenResponse) ||
typeof tokenResponse.access_token !== 'string' ||
tokenResponse.access_token.trim().length === 0) {
throw new OpenAIError("Token exchange response missing 'access_token' field");
}
const accessToken = tokenResponse.access_token;
const expiresIn = tokenResponse.expires_in ?? 3600;
const expiresAt = Date.now() + expiresIn * 1000;
this.cachedToken = {
token: accessToken,
expiresAt,
};
return accessToken;
}
isTokenExpired(cachedToken) {
return Date.now() >= cachedToken.expiresAt;
}
needsRefresh(cachedToken) {
const bufferSeconds = this.config.refreshBufferSeconds ?? 1200;
const bufferMs = bufferSeconds * 1000;
return Date.now() >= cachedToken.expiresAt - bufferMs;
}
invalidateToken() {
this.cachedToken = null;
this.refreshPromise = null;
}
}
//# sourceMappingURL=workload-identity-auth.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"workload-identity-auth.mjs","sourceRoot":"","sources":["../src/auth/workload-identity-auth.ts"],"names":[],"mappings":"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"}