diff --git a/packages/hoppscotch-common/src/components/http/OAuth2Authorization.vue b/packages/hoppscotch-common/src/components/http/OAuth2Authorization.vue
index fbd157170..ee9d2f1c0 100644
--- a/packages/hoppscotch-common/src/components/http/OAuth2Authorization.vue
+++ b/packages/hoppscotch-common/src/components/http/OAuth2Authorization.vue
@@ -3,14 +3,25 @@
-
+
-
+
@@ -44,6 +55,7 @@ import { useToast } from "@composables/toast"
import { tokenRequest } from "~/helpers/oauth"
import { getCombinedEnvVariables } from "~/helpers/preRequest"
import * as E from "fp-ts/Either"
+import { computed } from "vue"
const t = useI18n()
const toast = useToast()
@@ -66,10 +78,16 @@ watch(
)
const oidcDiscoveryURL = pluckRef(auth, "oidcDiscoveryURL")
+const hasOIDCURL = computed(() => {
+ return oidcDiscoveryURL.value
+})
const authURL = pluckRef(auth, "authURL")
const accessTokenURL = pluckRef(auth, "accessTokenURL")
+const hasAccessTokenOrAuthURL = computed(() => {
+ return accessTokenURL.value || authURL.value
+})
const clientID = pluckRef(auth, "clientID")
@@ -88,13 +106,11 @@ function translateTokenRequestError(error: string) {
}
const handleAccessTokenRequest = async () => {
- if (
- oidcDiscoveryURL.value === "" &&
- (authURL.value === "" || accessTokenURL.value === "")
- ) {
+ if (!oidcDiscoveryURL.value && !(authURL.value || accessTokenURL.value)) {
toast.error(`${t("error.incomplete_config_urls")}`)
return
}
+
const envs = getCombinedEnvVariables()
const envVars = [...envs.selected, ...envs.global]
diff --git a/packages/hoppscotch-common/src/helpers/oauth.ts b/packages/hoppscotch-common/src/helpers/oauth.ts
index db52ef5f0..ce45432be 100644
--- a/packages/hoppscotch-common/src/helpers/oauth.ts
+++ b/packages/hoppscotch-common/src/helpers/oauth.ts
@@ -3,41 +3,20 @@ import { PersistenceService } from "~/services/persistence"
import * as E from "fp-ts/Either"
import { z } from "zod"
+import { InterceptorService } from "~/services/interceptor.service"
+import { ExtensionInterceptorService } from "~/platform/std/interceptors/extension"
+
+import { AxiosRequestConfig } from "axios"
+import { until } from "@vueuse/core"
const redirectUri = `${window.location.origin}/oauth`
+const interceptorService = getService(InterceptorService)
const persistenceService = getService(PersistenceService)
+const extensionService = getService(ExtensionInterceptorService)
// GENERAL HELPER FUNCTIONS
-/**
- * Makes a POST request and parse the response as JSON
- *
- * @param {String} url - The resource
- * @param {Object} params - Configuration options
- * @returns {Object}
- */
-
-const sendPostRequest = async (url: string, params: Record) => {
- const body = Object.keys(params)
- .map((key) => `${key}=${params[key]}`)
- .join("&")
- const options = {
- method: "POST",
- headers: {
- "Content-type": "application/x-www-form-urlencoded; charset=UTF-8",
- },
- body,
- }
- try {
- const response = await fetch(url, options)
- const data = await response.json()
- return E.right(data)
- } catch (e) {
- return E.left("AUTH_TOKEN_REQUEST_FAILED")
- }
-}
-
/**
* Parse a query string into an object
*
@@ -71,9 +50,16 @@ const getTokenConfiguration = async (endpoint: string) => {
},
}
try {
- const response = await fetch(endpoint, options)
- const config = await response.json()
- return E.right(config)
+ const res = await runRequestThroughInterceptor({
+ url: endpoint,
+ ...options,
+ })
+
+ if (E.isLeft(res)) {
+ return E.left("OIDC_DISCOVERY_FAILED")
+ }
+
+ return E.right(JSON.parse(res.right))
} catch (e) {
return E.left("OIDC_DISCOVERY_FAILED")
}
@@ -166,8 +152,7 @@ const tokenRequest = async ({
clientSecret,
scope,
}: TokenRequestParams) => {
- // Check oauth configuration
- if (oidcDiscoveryUrl !== "") {
+ if (oidcDiscoveryUrl) {
const res = await getTokenConfiguration(oidcDiscoveryUrl)
const OIDCConfigurationSchema = z.object({
@@ -269,17 +254,19 @@ const handleOAuthRedirect = async () => {
}
// Exchange the authorization code for an access token
- const tokenResponse: E.Either = await sendPostRequest(
- tokenEndpoint,
- {
+ const tokenResponse = await runRequestThroughInterceptor({
+ url: tokenEndpoint,
+ data: JSON.stringify({
grant_type: "authorization_code",
code: queryParams.code,
client_id: clientID,
client_secret: clientSecret,
redirect_uri: redirectUri,
code_verifier: codeVerifier,
- }
- )
+ }),
+ method: "POST",
+ headers: {},
+ })
// Clean these up since we don't need them anymore
clearPKCEState()
@@ -293,7 +280,7 @@ const handleOAuthRedirect = async () => {
})
const parsedTokenResponse = withAccessTokenSchema.safeParse(
- tokenResponse.right
+ JSON.parse(tokenResponse.right)
)
return parsedTokenResponse.success
@@ -309,4 +296,20 @@ const clearPKCEState = () => {
persistenceService.removeLocalConfig("client_secret")
}
+async function runRequestThroughInterceptor(config: AxiosRequestConfig) {
+ const res = await interceptorService.runRequest(config).response
+
+ if (E.isLeft(res)) {
+ return E.left("REQUEST_FAILED")
+ }
+
+ // convert ArrayBuffer to string
+ if (!(res.right.data instanceof ArrayBuffer)) {
+ return E.left("REQUEST_FAILED")
+ }
+
+ const data = new TextDecoder().decode(res.right.data).replace(/\0+$/, "")
+ return E.right(data)
+}
+
export { tokenRequest, handleOAuthRedirect }
diff --git a/packages/hoppscotch-common/src/platform/std/interceptors/extension.ts b/packages/hoppscotch-common/src/platform/std/interceptors/extension.ts
index 033e23865..a6095c0bc 100644
--- a/packages/hoppscotch-common/src/platform/std/interceptors/extension.ts
+++ b/packages/hoppscotch-common/src/platform/std/interceptors/extension.ts
@@ -13,6 +13,7 @@ import { browserIsChrome, browserIsFirefox } from "~/helpers/utils/userAgent"
import SettingsExtension from "~/components/settings/Extension.vue"
import InterceptorsExtensionSubtitle from "~/components/interceptors/ExtensionSubtitle.vue"
import InterceptorsErrorPlaceholder from "~/components/interceptors/ErrorPlaceholder.vue"
+import { until } from "@vueuse/core"
export const defineSubscribableObject = (obj: T) => {
const proxyObject = {
@@ -206,6 +207,14 @@ export class ExtensionInterceptorService
private async runRequestOnExtension(
req: AxiosRequestConfig
): RequestRunResult["response"] {
+ // wait for the extension to resolve
+ await until(this.extensionStatus).toMatch(
+ (status) => status !== "waiting",
+ {
+ timeout: 1000,
+ }
+ )
+
const extensionHook = window.__POSTWOMAN_EXTENSION_HOOK__
if (!extensionHook) {
return E.left({