diff --git a/components/http/Authorization.vue b/components/http/Authorization.vue
index 1139b8a17..c7db46bf9 100644
--- a/components/http/Authorization.vue
+++ b/components/http/Authorization.vue
@@ -53,9 +53,22 @@
$refs.authTypeOptions.tippy().hide()
"
/>
+
+
-
+
+
+
+
+
+
+
+
+ {{ $t("helpers.authorization") }}
+
+
+
+
@@ -175,6 +206,7 @@ import { computed, defineComponent, Ref, ref } from "@nuxtjs/composition-api"
import {
HoppRESTAuthBasic,
HoppRESTAuthBearer,
+ HoppRESTAuthOAuth2,
} from "~/helpers/types/HoppRESTAuth"
import { pluckRef, useStream } from "~/helpers/utils/composables"
import { restAuth$, setRESTAuth } from "~/newstore/RESTSession"
@@ -192,6 +224,7 @@ export default defineComponent({
const authName = computed(() => {
if (authType.value === "basic") return "Basic Auth"
else if (authType.value === "bearer") return "Bearer"
+ else if (authType.value === "oauth-2") return "OAuth 2.0"
else return "None"
})
const authActive = pluckRef(auth, "authActive")
@@ -201,6 +234,8 @@ export default defineComponent({
const bearerToken = pluckRef(auth as Ref, "token")
+ const oauth2Token = pluckRef(auth as Ref, "token")
+
const URLExcludes = useSetting("URL_EXCLUDES")
const passwordFieldType = ref("password")
@@ -226,6 +261,7 @@ export default defineComponent({
basicUsername,
basicPassword,
bearerToken,
+ oauth2Token,
URLExcludes,
passwordFieldType,
clearContent,
diff --git a/components/http/OAuth2Authorization.vue b/components/http/OAuth2Authorization.vue
new file mode 100644
index 000000000..a91f1fe56
--- /dev/null
+++ b/components/http/OAuth2Authorization.vue
@@ -0,0 +1,136 @@
+
+
+
+
+
diff --git a/helpers/oauth.js b/helpers/oauth.js
index 019536f22..6a317d4d2 100644
--- a/helpers/oauth.js
+++ b/helpers/oauth.js
@@ -198,7 +198,7 @@ const tokenRequest = async ({
* Handle the redirect back from the authorization server and
* get an access token from the token endpoint
*
- * @returns {Object}
+ * @returns {Promise}
*/
const oauthRedirect = () => {
@@ -213,6 +213,7 @@ const oauthRedirect = () => {
// Verify state matches what we set at the beginning
if (getLocalConfig("pkce_state") !== q.state) {
alert("Invalid state")
+ Promise.reject(tokenResponse)
} else {
try {
// Exchange the authorization code for an access token
@@ -225,6 +226,7 @@ const oauthRedirect = () => {
})
} catch (e) {
console.error(e)
+ return Promise.reject(tokenResponse)
}
}
// Clean these up since we don't need them anymore
@@ -234,7 +236,7 @@ const oauthRedirect = () => {
removeLocalConfig("client_id")
return tokenResponse
}
- return tokenResponse
+ return Promise.reject(tokenResponse)
}
export { tokenRequest, oauthRedirect }
diff --git a/helpers/types/HoppRESTAuth.ts b/helpers/types/HoppRESTAuth.ts
index 3076c9d3c..8cbcd92ac 100644
--- a/helpers/types/HoppRESTAuth.ts
+++ b/helpers/types/HoppRESTAuth.ts
@@ -15,8 +15,20 @@ export type HoppRESTAuthBearer = {
token: string
}
+export type HoppRESTAuthOAuth2 = {
+ authType: "oauth-2"
+
+ token: string
+ oidcDiscoveryURL: string
+ authURL: string
+ accessTokenURL: string
+ clientID: string
+ scope: string
+}
+
export type HoppRESTAuth = { authActive: boolean } & (
| HoppRESTAuthNone
| HoppRESTAuthBasic
| HoppRESTAuthBearer
+ | HoppRESTAuthOAuth2
)
diff --git a/helpers/utils/EffectiveURL.ts b/helpers/utils/EffectiveURL.ts
index e97466837..b81ed5e0f 100644
--- a/helpers/utils/EffectiveURL.ts
+++ b/helpers/utils/EffectiveURL.ts
@@ -87,7 +87,10 @@ export function getEffectiveRESTRequest(
`${request.auth.username}:${request.auth.password}`
)}`,
})
- } else if (request.auth.authType === "bearer") {
+ } else if (
+ request.auth.authType === "bearer" ||
+ request.auth.authType === "oauth-2"
+ ) {
effectiveFinalHeaders.push({
active: true,
key: "Authorization",
diff --git a/newstore/settings.ts b/newstore/settings.ts
index b3c32168a..969d61271 100644
--- a/newstore/settings.ts
+++ b/newstore/settings.ts
@@ -43,6 +43,7 @@ export type SettingsType = {
httpUser: boolean
httpPassword: boolean
bearerToken: boolean
+ oauth2Token: boolean
}
THEME_COLOR: HoppAccentColor
BG_COLOR: HoppBgColor
@@ -68,6 +69,7 @@ export const defaultSettings: SettingsType = {
httpUser: true,
httpPassword: true,
bearerToken: true,
+ oauth2Token: true,
},
THEME_COLOR: "blue",
BG_COLOR: "system",
diff --git a/pages/index.vue b/pages/index.vue
index 6621c124f..746934677 100644
--- a/pages/index.vue
+++ b/pages/index.vue
@@ -84,8 +84,10 @@ import {
computed,
defineComponent,
getCurrentInstance,
+ onBeforeMount,
onBeforeUnmount,
onMounted,
+ Ref,
ref,
useContext,
watch,
@@ -94,6 +96,7 @@ import { Splitpanes, Pane } from "splitpanes"
import "splitpanes/dist/splitpanes.css"
import { map } from "rxjs/operators"
import { Subscription } from "rxjs"
+import isEqual from "lodash/isEqual"
import { useSetting } from "~/newstore/settings"
import {
restRequest$,
@@ -101,9 +104,12 @@ import {
restActiveHeadersCount$,
getRESTRequest,
setRESTRequest,
+ setRESTAuth,
+ restAuth$,
} from "~/newstore/RESTSession"
import { translateExtURLParams } from "~/helpers/RESTExtURLParams"
import {
+ pluckRef,
useReadonlyStream,
useStream,
useStreamSubscriber,
@@ -111,6 +117,8 @@ import {
import { loadRequestFromSync, startRequestSync } from "~/helpers/fb/request"
import { onLoggedIn } from "~/helpers/fb/auth"
import { HoppRESTRequest } from "~/helpers/types/HoppRESTRequest"
+import { oauthRedirect } from "~/helpers/oauth"
+import { HoppRESTAuthOAuth2 } from "~/helpers/types/HoppRESTAuth"
function bindRequestToURLParams() {
const {
@@ -159,12 +167,36 @@ function bindRequestToURLParams() {
onMounted(() => {
const query = route.value.query
- if (Object.keys(query).length === 0) return
+ // If query params are empty, or contains code or error param (these are from Oauth Redirect)
+ // We skip URL params parsing
+ if (Object.keys(query).length === 0 || query.code || query.error) return
setRESTRequest(translateExtURLParams(query))
})
}
-function setupRequestSync() {
+function oAuthURL() {
+ const auth = useStream(
+ restAuth$,
+ { authType: "none", authActive: true },
+ setRESTAuth
+ )
+
+ const oauth2Token = pluckRef(auth as Ref, "token")
+
+ onBeforeMount(async () => {
+ const tokenInfo = await oauthRedirect()
+ if (Object.prototype.hasOwnProperty.call(tokenInfo, "access_token")) {
+ if (typeof tokenInfo === "object") {
+ oauth2Token.value = tokenInfo.access_token
+ }
+ }
+ })
+}
+
+function setupRequestSync(
+ confirmSync: Ref,
+ requestForSync: Ref
+) {
const { route } = useContext()
// Subscription to request sync
@@ -172,13 +204,18 @@ function setupRequestSync() {
// Load request on login resolve and start sync
onLoggedIn(async () => {
- if (Object.keys(route.value.query).length === 0) {
+ if (
+ Object.keys(route.value.query).length === 0 &&
+ !(route.value.query.code || route.value.query.error)
+ ) {
const request = await loadRequestFromSync()
if (request) {
console.log("sync le request nnd")
-
- setRESTRequest(request)
- // confirmSync.value = true
+ // setRESTRequest(request)
+ if (!isEqual(request, getRESTRequest())) {
+ requestForSync.value = request
+ confirmSync.value = true
+ }
}
}
@@ -194,19 +231,21 @@ function setupRequestSync() {
export default defineComponent({
components: { Splitpanes, Pane },
setup() {
+ const requestForSync = ref(null)
+
const confirmSync = ref(false)
const internalInstance = getCurrentInstance()
console.log("yoo", internalInstance)
- const syncRequest = (request: HoppRESTRequest) => {
+ const syncRequest = () => {
console.log("syncinggg")
- setRESTRequest(request)
+ setRESTRequest(requestForSync.value!)
}
const { subscribeToStream } = useStreamSubscriber()
- setupRequestSync()
+ setupRequestSync(confirmSync, requestForSync)
bindRequestToURLParams()
subscribeToStream(restRequest$, (x) => {
@@ -238,6 +277,8 @@ export default defineComponent({
EXPERIMENTAL_URL_BAR_ENABLED: useSetting("EXPERIMENTAL_URL_BAR_ENABLED"),
confirmSync,
syncRequest,
+ oAuthURL,
+ requestForSync,
}
},
})