diff --git a/index.html b/index.html
index f518d15..9595a13 100644
--- a/index.html
+++ b/index.html
@@ -36,7 +36,7 @@
const clientProvider = new DynamicRegistrationClientProvider
const cachingClientProvider = new CachingClientProvider(clientProvider)
- const dPoPTokenProvider = new DPoPTokenProvider(callbackUri, ui.getCode.bind(ui), cachingASProvider, cachingClientProvider)
+ const dPoPTokenProvider = new DPoPTokenProvider(callbackUri, ui, cachingASProvider, cachingClientProvider)
const fetch = new ReactiveFetchManager([dPoPTokenProvider]).fetch
diff --git a/src/AuthorizationCodeFlow.ts b/src/AuthorizationCodeFlow.ts
index 36adfce..d6b88c2 100644
--- a/src/AuthorizationCodeFlow.ts
+++ b/src/AuthorizationCodeFlow.ts
@@ -1,5 +1,6 @@
import { Mutex } from "./Mutex.js"
import { CodeRequestCancelledError } from "./CodeRequestCancelledError.js"
+import type { CodeProvider } from "./CodeProvider.js"
const authorizationWindowName = "oidcAuthentication"
const onlyOnce = {once: true}
@@ -119,7 +120,7 @@ const html = `
*
* ```
*/
-export class AuthorizationCodeFlow extends HTMLElement {
+export class AuthorizationCodeFlow extends HTMLElement implements CodeProvider {
readonly #mutex = new Mutex
#newModal!: HTMLDialogElement
#switchModal!: HTMLDialogElement
@@ -194,7 +195,6 @@ export class AuthorizationCodeFlow extends HTMLElement {
this.ownerDocument.defaultView?.removeEventListener("message", onMessage)
signal.removeEventListener("abort", onAbort)
this.#switchModal.close()
- this.#authorizationWindow?.close()
respondWithCode(message.data)
}
@@ -218,6 +218,10 @@ export class AuthorizationCodeFlow extends HTMLElement {
return await responseFromPopup
}
+ cleanup(): void {
+ this.#authorizationWindow?.close()
+ }
+
#onSubmit(e: SubmitEvent) {
e.preventDefault()
diff --git a/src/BearerTokenProvider.ts b/src/BearerTokenProvider.ts
index 051af48..52a5259 100644
--- a/src/BearerTokenProvider.ts
+++ b/src/BearerTokenProvider.ts
@@ -1,15 +1,15 @@
import * as oauth from "oauth4webapi"
-import { GetCodeCallback } from "./GetCodeCallback.js"
+import { CodeProvider } from "./CodeProvider.js"
import { TokenProvider } from "./TokenProvider.js"
// TODO: Configure properly for insecure localhost only
const oauthAllowInsecureRequests = true
export class BearerTokenProvider implements TokenProvider {
- readonly #getCode: GetCodeCallback
+ readonly #codeProvider: CodeProvider
- constructor(getCodeCallback: GetCodeCallback) {
- this.#getCode = getCodeCallback
+ constructor(codeProvider: CodeProvider) {
+ this.#codeProvider = codeProvider
}
async #getIssuer(request: Request): Promise {
@@ -75,7 +75,7 @@ export class BearerTokenProvider implements TokenProvider {
// authorizationUrl.searchParams.set("nonce", nonce)
// }
- const authorizationCodeResponse = await this.#getCode(authorizationUrl, request.signal)
+ const authorizationCodeResponse = await this.#codeProvider.getCode(authorizationUrl, request.signal)
const authorizationCodeParams = oauth.validateAuthResponse(authorizationServer, clientRegistration, new URL(authorizationCodeResponse))
let clientAuth = oauth.None()
diff --git a/src/CodeProvider.ts b/src/CodeProvider.ts
new file mode 100644
index 0000000..aac64eb
--- /dev/null
+++ b/src/CodeProvider.ts
@@ -0,0 +1,5 @@
+export interface CodeProvider {
+ getCode(authorizationUri: URL, signal: AbortSignal): Promise
+
+ cleanup(): void
+}
diff --git a/src/DPoPTokenProvider.ts b/src/DPoPTokenProvider.ts
index 17e0123..b953ea9 100644
--- a/src/DPoPTokenProvider.ts
+++ b/src/DPoPTokenProvider.ts
@@ -1,6 +1,6 @@
import * as oauth from "oauth4webapi"
import * as DPoP from "dpop"
-import type { GetCodeCallback } from "./GetCodeCallback.js"
+import type { CodeProvider } from "./CodeProvider.js"
import type { TokenProvider } from "./TokenProvider.js"
import type { AuthorizationServerProvider } from "./AuthorizationServerProvider.js"
import { ClientProvider } from "./ClientProvider.js"
@@ -8,14 +8,14 @@ import { ClientProvider } from "./ClientProvider.js"
type CacheEntry = { created: number, tokenResult: oauth.TokenEndpointResponse, dpopKey: CryptoKeyPair }
export class DPoPTokenProvider implements TokenProvider {
- readonly #getCode: GetCodeCallback
+ readonly #codeProvider: CodeProvider
readonly #callbackUri: string
readonly #cache = new Map // TODO: Take cache from caller
readonly #asProvider: AuthorizationServerProvider
readonly #clientProvider: ClientProvider
- constructor(callbackUri: string, getCodeCallback: GetCodeCallback, asProvider: AuthorizationServerProvider, clientProvider: ClientProvider) {
- this.#getCode = getCodeCallback
+ constructor(callbackUri: string, codeProvider: CodeProvider, asProvider: AuthorizationServerProvider, clientProvider: ClientProvider) {
+ this.#codeProvider = codeProvider
this.#callbackUri = callbackUri
this.#asProvider = asProvider
this.#clientProvider = clientProvider
@@ -73,7 +73,7 @@ export class DPoPTokenProvider implements TokenProvider {
}
}
- const authorizationCodeResponse = await this.#getCode(authorizationUrl, request.signal)
+ const authorizationCodeResponse = await this.#codeProvider.getCode(authorizationUrl, request.signal)
let authorizationCodeParams
try {
@@ -89,13 +89,14 @@ export class DPoPTokenProvider implements TokenProvider {
console.debug("Authorization server requires user interaction, retrying without prompt")
authorizationUrl.searchParams.delete("prompt")
- const authorizationCodeResponse = await this.#getCode(authorizationUrl, request.signal)
+ const authorizationCodeResponse = await this.#codeProvider.getCode(authorizationUrl, request.signal)
authorizationCodeParams = oauth.validateAuthResponse(authorizationServer, clientRegistration, new URL(authorizationCodeResponse), state)
} else {
throw e
}
}
+ this.#codeProvider.cleanup()
const tokenResponse = await oauth.authorizationCodeGrantRequest(authorizationServer, clientRegistration, this.getClientAuth(authorizationServer.issuer, clientRegistration), authorizationCodeParams, this.#callbackUri, authorizationServer.code_challenge_methods_supported !== undefined ? codeVerifier : oauth.nopkce, {DPoP: dpop, signal: request.signal})
const tokenResult = await oauth.processAuthorizationCodeResponse(authorizationServer, clientRegistration, tokenResponse, {expectedNonce: this.nonceVerificationOverride(authorizationServer.issuer, nonce)})
diff --git a/src/GetCodeCallback.ts b/src/GetCodeCallback.ts
deleted file mode 100644
index 6d0e672..0000000
--- a/src/GetCodeCallback.ts
+++ /dev/null
@@ -1 +0,0 @@
-export type GetCodeCallback = (authorizationUri: URL, signal: AbortSignal) => Promise
\ No newline at end of file
diff --git a/src/ReactiveFetchWorkerManager.ts b/src/ReactiveFetchWorkerManager.ts
index ce8b41c..186f039 100644
--- a/src/ReactiveFetchWorkerManager.ts
+++ b/src/ReactiveFetchWorkerManager.ts
@@ -1,10 +1,10 @@
-import type { GetCodeCallback } from "./GetCodeCallback.js"
+import type { CodeProvider } from "./CodeProvider.js"
export class ReactiveFetchWorkerManager {
- readonly #getCode: GetCodeCallback
+ readonly #codeProvider: CodeProvider
- constructor(getCodeCallback: GetCodeCallback) {
- this.#getCode = getCodeCallback
+ constructor(codeProvider: CodeProvider) {
+ this.#codeProvider = codeProvider
}
async register() {
@@ -15,6 +15,6 @@ export class ReactiveFetchWorkerManager {
}
async #onMessage(e: MessageEvent) {
- e.ports[0]?.postMessage(await this.#getCode(new URL(e.data), null!)) // TODO: Signal?
+ e.ports[0]?.postMessage(await this.#codeProvider.getCode(new URL(e.data), null!)) // TODO: Signal?
}
}
diff --git a/src/mod.ts b/src/mod.ts
index 7fed984..5441d6c 100644
--- a/src/mod.ts
+++ b/src/mod.ts
@@ -6,7 +6,7 @@ export * from "./ReactiveFetchWorkerManager.js"
export * from "./CodeRequestCancelledError.js"
export * from "./ReactiveAuthenticationError.js"
export * from "./ClientCredentialsTokenProvider.js"
-export * from "./GetCodeCallback.js"
+export * from "./CodeProvider.js"
export * from "./PatternIssuerProvider.js"
export * from "./TokenProvider.js"
export * from "./IssuerProvider.js"
diff --git a/src/reactive-fetch-worker.ts b/src/reactive-fetch-worker.ts
index 2e9a310..a1e9904 100644
--- a/src/reactive-fetch-worker.ts
+++ b/src/reactive-fetch-worker.ts
@@ -28,8 +28,8 @@ async function onFetch(e: FetchEvent): Promise {
}
function upgrade(request: Request, client: Client): Promise {
- const dPoPTokenProvider = new DPoPTokenProvider(undefined!, postEventAndWait.bind(undefined, client), undefined!, undefined!) // TODO: Callback, getIssuer, getClient
- const bearerProvider = new BearerTokenProvider(postEventAndWait.bind(undefined, client))
+ const dPoPTokenProvider = new DPoPTokenProvider(undefined!, undefined!, undefined!, undefined!) // TODO: Callback, getIssuer, getClient
+ const bearerProvider = new BearerTokenProvider(undefined!)
return new ReactiveAuthenticationClient(self.fetch, [bearerProvider, dPoPTokenProvider]).fetch(request)
}