Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
}
</script>
<script type="module">
import { DPoPTokenProvider, ReactiveFetchManager } from "./dist/mod.js"
import { DPoPTokenProvider, InsecureConfiguration, ReactiveFetchManager } from "./dist/mod.js"
import "./dist/registerElements.js"

/* Demo talks to a local Community Solid Server over plain HTTP */
InsecureConfiguration.allow()

/* Reactive fetch infrastructure */
const ui = document.querySelector("authorization-code-flow")
const issuerUi = document.querySelector("idp-picker")
Expand Down
10 changes: 4 additions & 6 deletions src/BearerTokenProvider.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import * as oauth from "oauth4webapi"
import { GetCodeCallback } from "./GetCodeCallback.js"
import { TokenProvider } from "./TokenProvider.js"

// TODO: Configure properly for insecure localhost only
const oauthAllowInsecureRequests = true
import { InsecureConfiguration } from "./InsecureConfiguration.js"

export class BearerTokenProvider implements TokenProvider {
readonly #getCode: GetCodeCallback
Expand Down Expand Up @@ -43,12 +41,12 @@ export class BearerTokenProvider implements TokenProvider {
async upgrade(request: Request): Promise<Request> {
const issuer = await this.#getIssuer(request)

const discoveryResponse = await oauth.discoveryRequest(issuer, {[oauth.allowInsecureRequests]: oauthAllowInsecureRequests})
const discoveryResponse = await oauth.discoveryRequest(issuer, InsecureConfiguration.requestOptions)
const authorizationServer = await oauth.processDiscoveryResponse(issuer, discoveryResponse)

const callbackUri = await this.#getCallback(request)

const registrationResponse = await oauth.dynamicClientRegistrationRequest(authorizationServer, {redirect_uris: [callbackUri]}, {[oauth.allowInsecureRequests]: oauthAllowInsecureRequests})
const registrationResponse = await oauth.dynamicClientRegistrationRequest(authorizationServer, {redirect_uris: [callbackUri]}, InsecureConfiguration.requestOptions)
const clientRegistration = await oauth.processDynamicClientRegistrationResponse(registrationResponse)
const [registeredRedirectUri] = clientRegistration.redirect_uris as string[]
const [registeredResponseType] = clientRegistration.response_types as string[]
Expand Down Expand Up @@ -84,7 +82,7 @@ export class BearerTokenProvider implements TokenProvider {
clientAuth = authenticationMethod(clientSecret)
}

const tokenResponse = await oauth.authorizationCodeGrantRequest(authorizationServer, clientRegistration, clientAuth, authorizationCodeParams, callbackUri, codeVerifier, {[oauth.allowInsecureRequests]: oauthAllowInsecureRequests})
const tokenResponse = await oauth.authorizationCodeGrantRequest(authorizationServer, clientRegistration, clientAuth, authorizationCodeParams, callbackUri, codeVerifier, InsecureConfiguration.requestOptions)

// jwt nonce missing in igrant
// const tokenResult = await oauth.processAuthorizationCodeResponse(authorizationServer, clientRegistration, tokenResponse, {expectedNonce: nonce})
Expand Down
7 changes: 5 additions & 2 deletions src/ClientCredentialsTokenProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as oauth from "oauth4webapi"
import { AuthorizationServer } from "oauth4webapi"
import * as DPoP from "dpop"
import type { TokenProvider } from "./TokenProvider.js"
import { InsecureConfiguration } from "./InsecureConfiguration.js"

export class ClientCredentialsTokenProvider implements TokenProvider {
constructor(private clientId: string, private clientSecret: string) {
Expand Down Expand Up @@ -35,7 +36,8 @@ export class ClientCredentialsTokenProvider implements TokenProvider {
const issuer = await this.#getIssuer(request)

const discoveryResponse = await oauth.discoveryRequest(issuer, {
signal: request.signal
signal: request.signal,
...InsecureConfiguration.requestOptions
})
const authorizationServer = await oauth.processDiscoveryResponse(issuer, discoveryResponse)

Expand All @@ -46,7 +48,8 @@ export class ClientCredentialsTokenProvider implements TokenProvider {

const tokenResponse = await oauth.clientCredentialsGrantRequest(authorizationServer, clientRegistration, this.getClientAuth(authorizationServer, clientRegistration), {scope: "webid"}, {
DPoP: dpop,
signal: request.signal
signal: request.signal,
...InsecureConfiguration.requestOptions
})

const tokenResult = await oauth.processClientCredentialsResponse(authorizationServer, clientRegistration, tokenResponse)
Expand Down
7 changes: 4 additions & 3 deletions src/DPoPTokenProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as DPoP from "dpop"
import type { GetCodeCallback } from "./GetCodeCallback.js"
import type { TokenProvider } from "./TokenProvider.js"
import type { GetIssuerCallback } from "./GetIssuerCallback.js"
import { InsecureConfiguration } from "./InsecureConfiguration.js"

export class DPoPTokenProvider implements TokenProvider {
readonly #getCode: GetCodeCallback
Expand All @@ -22,10 +23,10 @@ export class DPoPTokenProvider implements TokenProvider {
async upgrade(request: Request): Promise<Request> {
const issuer = await this.#getIssuer(request)

const discoveryResponse = await oauth.discoveryRequest(issuer, {signal: request.signal})
const discoveryResponse = await oauth.discoveryRequest(issuer, {signal: request.signal, ...InsecureConfiguration.requestOptions})
const authorizationServer = await oauth.processDiscoveryResponse(issuer, discoveryResponse)

const registrationResponse = await oauth.dynamicClientRegistrationRequest(authorizationServer, {redirect_uris: [this.#callbackUri]}, {signal: request.signal})
const registrationResponse = await oauth.dynamicClientRegistrationRequest(authorizationServer, {redirect_uris: [this.#callbackUri]}, {signal: request.signal, ...InsecureConfiguration.requestOptions})
const clientRegistration = await oauth.processDynamicClientRegistrationResponse(registrationResponse)
const [registeredRedirectUri] = clientRegistration.redirect_uris as string[]
const [registeredResponseType] = clientRegistration.response_types as string[]
Expand Down Expand Up @@ -79,7 +80,7 @@ export class DPoPTokenProvider implements TokenProvider {
}
}

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 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, ...InsecureConfiguration.requestOptions})

const tokenResult = await oauth.processAuthorizationCodeResponse(authorizationServer, clientRegistration, tokenResponse, {expectedNonce: this.nonceVerificationOverride(authorizationServer.issuer, nonce)})

Expand Down
29 changes: 29 additions & 0 deletions src/InsecureConfiguration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as oauth from "oauth4webapi"

/**
* Global opt-in switch for oauth4webapi's HTTPS enforcement.
*
* @remarks
* Enforcement is on by default. Consumers targeting a plain HTTP issuer, such as a
* Community Solid Server on `http://localhost:3000`, opt out for themselves.
*/
export class InsecureConfiguration {
static #allowed = false

/**
* Allows OAuth requests over plain HTTP.
*
* @remarks
* Deprecated on purpose, so that consumers see the security implication at the call site.
*
* @deprecated Only ever call this in local development.
*/
static allow() {
console.error("Insecure requests allowed for oauth4webapi")
this.#allowed = true
}

static get requestOptions(): {[oauth.allowInsecureRequests]?: boolean} {
return {[oauth.allowInsecureRequests]: this.#allowed}
}
}
1 change: 1 addition & 0 deletions src/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export * from "./IdpPicker.js"
export * from "./WebIdPicker.js"
export * from "./WebIdRequestCancelledError.js"
export * from "./IssuerRequestCancelledError.js"
export * from "./InsecureConfiguration.js"
Loading