Skip to content

Commit

Permalink
feat: oauth revamp with grant types
Browse files Browse the repository at this point in the history
  • Loading branch information
amk-dev committed Mar 11, 2024
1 parent 68e439d commit 0e12233
Show file tree
Hide file tree
Showing 35 changed files with 2,089 additions and 255 deletions.
1 change: 1 addition & 0 deletions packages/hoppscotch-cli/src/options/test/env.ts
Expand Up @@ -42,6 +42,7 @@ export async function parseEnvsData(path: string) {

if (HoppEnvKeyPairResult.success) {
for (const [key, value] of Object.entries(HoppEnvKeyPairResult.data)) {
// PR-COMMENT: type error
envPairs.push({ key, value });
}
} else if (HoppEnvExportObjectResult.type === "ok") {
Expand Down
13 changes: 9 additions & 4 deletions packages/hoppscotch-cli/src/utils/pre-request.ts
Expand Up @@ -113,13 +113,18 @@ export function getEffectiveRESTRequest(
request.auth.authType === "bearer" ||
request.auth.authType === "oauth-2"
) {
const requestAuth = request.auth;

const isOAuth2 = requestAuth.authType === "oauth-2";

const token = isOAuth2
? requestAuth.grantTypeInfo.token
: requestAuth.token;

effectiveFinalHeaders.push({
active: true,
key: "Authorization",
value: `Bearer ${parseTemplateString(
request.auth.token,
envVariables
)}`,
value: `Bearer ${parseTemplateString(token, envVariables)}`,
});
} else if (request.auth.authType === "api-key") {
const { key, value, addTo } = request.auth;
Expand Down
30 changes: 18 additions & 12 deletions packages/hoppscotch-cli/src/utils/request.ts
Expand Up @@ -41,10 +41,10 @@ const processVariables = (variable: Environment["variables"][number]) => {
...variable,
value:
"value" in variable ? variable.value : process.env[variable.key] || "",
}
};
}
return variable
}
return variable;
};

/**
* Processes given envs, which includes processing each variable in global
Expand All @@ -56,10 +56,10 @@ const processEnvs = (envs: HoppEnvs) => {
const processedEnvs = {
global: envs.global.map(processVariables),
selected: envs.selected.map(processVariables),
}
};

return processedEnvs
}
return processedEnvs;
};

/**
* Transforms given request data to request-config used by request-runner to
Expand All @@ -70,7 +70,7 @@ const processEnvs = (envs: HoppEnvs) => {
export const createRequest = (req: EffectiveHoppRESTRequest): RequestConfig => {
const config: RequestConfig = {
supported: true,
displayUrl: req.effectiveFinalDisplayURL
displayUrl: req.effectiveFinalDisplayURL,
};
const { finalBody, finalEndpoint, finalHeaders, finalParams } = getRequest;
const reqParams = finalParams(req);
Expand Down Expand Up @@ -131,6 +131,7 @@ export const requestRunner =
let status: number;
const baseResponse = await axios(requestConfig);
const { config } = baseResponse;
// PR-COMMENT: type error
const runnerResponse: RequestRunnerResponse = {
...baseResponse,
endpoint: getRequest.endpoint(config.url),
Expand Down Expand Up @@ -257,10 +258,13 @@ export const processRequest =
let updatedEnvs = <HoppEnvs>{};

// Fetch values for secret environment variables from system environment
const processedEnvs = processEnvs(envs)
const processedEnvs = processEnvs(envs);

// Executing pre-request-script
const preRequestRes = await preRequestScriptRunner(request, processedEnvs)();
const preRequestRes = await preRequestScriptRunner(
request,
processedEnvs
)();
if (E.isLeft(preRequestRes)) {
printPreRequestRunner.fail();

Expand Down Expand Up @@ -347,7 +351,7 @@ export const processRequest =
*/
export const preProcessRequest = (
request: HoppRESTRequest,
collection: HoppCollection,
collection: HoppCollection
): HoppRESTRequest => {
const tempRequest = Object.assign({}, request);
const { headers: parentHeaders, auth: parentAuth } = collection;
Expand All @@ -372,8 +376,10 @@ export const preProcessRequest = (
// Filter out header entries present in the parent (folder/collection) under the same name
// This ensures the child headers take precedence over the parent headers
const filteredEntries = parentHeaders.filter((parentHeaderEntries) => {
return !tempRequest.headers.some((reqHeaderEntries) => reqHeaderEntries.key === parentHeaderEntries.key)
})
return !tempRequest.headers.some(
(reqHeaderEntries) => reqHeaderEntries.key === parentHeaderEntries.key
);
});
tempRequest.headers.push(...filteredEntries);
} else if (!tempRequest.headers) {
tempRequest.headers = [];
Expand Down
23 changes: 21 additions & 2 deletions packages/hoppscotch-common/locales/en.json
Expand Up @@ -137,7 +137,26 @@
"redirect_no_token_endpoint": "No Token Endpoint Defined",
"something_went_wrong_on_oauth_redirect": "Something went wrong during OAuth Redirect",
"something_went_wrong_on_token_generation": "Something went wrong on token generation",
"token_generation_oidc_discovery_failed": "Failure on token generation: OpenID Connect Discovery Failed"
"token_generation_oidc_discovery_failed": "Failure on token generation: OpenID Connect Discovery Failed",
"grant_type": "Grant Type",
"grant_type_auth_code": "Authorization Code",
"token_fetched_successfully": "Token fetched successfully",
"token_fetch_failed": "Failed to fetch token",
"validation_failed": "Validation Failed, please check the form fields",
"label_authorization_endpoint": "Authorization Endpoint",
"label_client_id": "Client ID",
"label_client_secret": "Client Secret",
"label_code_challenge": "Code Challenge",
"label_code_challenge_method": "Code Challenge Method",
"label_code_verifier": "Code Verifier",
"label_scopes": "Scopes",
"label_token_endpoint": "Token Endpoint",
"label_use_pkce": "Use PKCE",
"label_implicit": "Implicit",
"label_password": "Password",
"label_username": "Username",
"label_auth_code": "Authorization Code",
"label_client_credentials": "Client Credentials"
},
"pass_key_by": "Pass by",
"password": "Password",
Expand Down Expand Up @@ -283,7 +302,7 @@
"updated": "Environment updated",
"value": "Value",
"variable": "Variable",
"variables":"Variables",
"variables": "Variables",
"variable_list": "Variable List"
},
"error": {
Expand Down
13 changes: 7 additions & 6 deletions packages/hoppscotch-common/src/components.d.ts
@@ -1,11 +1,11 @@
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'

export {}

declare module '@vue/runtime-core' {
declare module 'vue' {
export interface GlobalComponents {
AppActionHandler: typeof import('./components/app/ActionHandler.vue')['default']
AppBanner: typeof import('./components/app/Banner.vue')['default']
Expand Down Expand Up @@ -124,13 +124,15 @@ declare module '@vue/runtime-core' {
HttpHeaders: typeof import('./components/http/Headers.vue')['default']
HttpImportCurl: typeof import('./components/http/ImportCurl.vue')['default']
HttpOAuth2Authorization: typeof import('./components/http/OAuth2Authorization.vue')['default']
HttpOAuth2AuthorizationNew: typeof import('./components/http/OAuth2AuthorizationNew.vue')['default']
HttpParameters: typeof import('./components/http/Parameters.vue')['default']
HttpPreRequestScript: typeof import('./components/http/PreRequestScript.vue')['default']
HttpRawBody: typeof import('./components/http/RawBody.vue')['default']
HttpReqChangeConfirmModal: typeof import('./components/http/ReqChangeConfirmModal.vue')['default']
HttpRequest: typeof import('./components/http/Request.vue')['default']
HttpRequestOptions: typeof import('./components/http/RequestOptions.vue')['default']
HttpRequestTab: typeof import('./components/http/RequestTab.vue')['default']
HttpRequestVariables: typeof import('./components/http/RequestVariables.vue')['default']
HttpResponse: typeof import('./components/http/Response.vue')['default']
HttpResponseMeta: typeof import('./components/http/ResponseMeta.vue')['default']
HttpSidebar: typeof import('./components/http/Sidebar.vue')['default']
Expand Down Expand Up @@ -209,5 +211,4 @@ declare module '@vue/runtime-core' {
WorkspaceCurrent: typeof import('./components/workspace/Current.vue')['default']
WorkspaceSelector: typeof import('./components/workspace/Selector.vue')['default']
}

}
Expand Up @@ -122,9 +122,11 @@ watch(
(show) => {
if (show && props.editingProperties?.collection) {
editableCollection.value.auth = clone(
// AM-REMINDER: errors from previous feature
props.editingProperties.collection.auth
)
editableCollection.value.headers = clone(
// AM-REMINDER: errors from previous feature
props.editingProperties.collection.headers
)
} else {
Expand Down
Expand Up @@ -128,8 +128,10 @@
:shortcut="['P']"
@click="
() => {
debugger
emit('edit-properties', {
collectionIndex: collectionIndex,
// AM-REMINDER: check this line, because collection is not defined anywhere
collection: collection,
})
hide()
Expand Down
Expand Up @@ -189,7 +189,7 @@
<div v-if="auth.authType === 'oauth-2'">
<div class="flex flex-1 border-b border-dividerLight">
<SmartEnvInput
v-model="auth.token"
v-model="auth.grantTypeInfo.token"
:environment-highlights="false"
placeholder="Token"
/>
Expand Down
Expand Up @@ -581,10 +581,16 @@ const getComputedAuthHeaders = (
request.auth.authType === "bearer" ||
request.auth.authType === "oauth-2"
) {
const requestAuth = request.auth
const isOAuth2 = requestAuth.authType === "oauth-2"
const token = isOAuth2 ? requestAuth.grantTypeInfo.token : requestAuth.token
headers.push({
active: true,
key: "Authorization",
value: `Bearer ${request.auth.token}`,
value: `Bearer ${token}`,
})
} else if (request.auth.authType === "api-key") {
const { key, addTo } = request.auth
Expand Down Expand Up @@ -661,6 +667,7 @@ const inheritedProperties = computed(() => {
const computedAuthHeader = getComputedAuthHeaders(
request.value,
// AM-COMMENT: look into this, GQLAuth not yet updated yet issue
props.inheritedProperties.auth.inheritedAuth
)[0]
Expand Down
36 changes: 31 additions & 5 deletions packages/hoppscotch-common/src/components/http/Authorization.vue
Expand Up @@ -82,7 +82,7 @@
:active="authName === 'OAuth 2.0'"
@click="
() => {
auth.authType = 'oauth-2'
selectOAuth2AuthType()
hide()
}
"
Expand Down Expand Up @@ -148,7 +148,7 @@
</template>
</HoppSmartPlaceholder>
<div v-else class="flex flex-1 border-b border-dividerLight">
<div class="w-2/3 border-r border-dividerLight">
<div class="w-2/3 border-r border-dividerLight flex justify-start">
<div v-if="auth.authType === 'basic'">
<HttpAuthorizationBasic v-model="auth" :envs="envs" />
</div>
Expand Down Expand Up @@ -177,10 +177,11 @@
/>
</div>
</div>
<div v-if="auth.authType === 'oauth-2'">
<div v-if="auth.authType === 'oauth-2'" class="w-full">
<div class="flex flex-1 border-b border-dividerLight">
<!-- AM-COMMENT: look into this -->
<SmartEnvInput
v-model="auth.token"
v-model="auth.grantTypeInfo.token"
placeholder="Token"
:envs="envs"
/>
Expand Down Expand Up @@ -217,7 +218,7 @@ import IconExternalLink from "~icons/lucide/external-link"
import IconCircleDot from "~icons/lucide/circle-dot"
import IconCircle from "~icons/lucide/circle"
import { computed, ref } from "vue"
import { HoppRESTAuth } from "@hoppscotch/data"
import { HoppRESTAuth, HoppRESTAuthOAuth2 } from "@hoppscotch/data"
import { pluckRef } from "@composables/ref"
import { useI18n } from "@composables/i18n"
import { useColorMode } from "@composables/theming"
Expand All @@ -226,6 +227,8 @@ import { onMounted } from "vue"
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
import { AggregateEnvironment } from "~/newstore/environments"
import { getDefaultAuthCodeOauthFlowParams } from "~/services/oauth/flows/authCode"
const t = useI18n()
const colorMode = useColorMode()
Expand Down Expand Up @@ -272,6 +275,29 @@ const getAuthName = (type: HoppRESTAuth["authType"] | undefined) => {
return AUTH_KEY_NAME[type] ? AUTH_KEY_NAME[type] : "None"
}
const selectOAuth2AuthType = () => {
const defaultGrantTypeInfo: HoppRESTAuthOAuth2["grantTypeInfo"] = {
...getDefaultAuthCodeOauthFlowParams(),
grantType: "AUTHORIZATION_CODE",
token: "",
}
// @ts-expect-error - the existing grantTypeInfo might be in the auth object, typescript doesnt know that
const existingGrantTypeInfo = auth.value.grantTypeInfo as
| HoppRESTAuthOAuth2["grantTypeInfo"]
| undefined
const grantTypeInfo = existingGrantTypeInfo
? existingGrantTypeInfo
: defaultGrantTypeInfo
auth.value = {
...auth.value,
authType: "oauth-2",
grantTypeInfo: grantTypeInfo,
}
}
const authActive = pluckRef(auth, "authActive")
const clearContent = () => {
Expand Down
1 change: 1 addition & 0 deletions packages/hoppscotch-common/src/components/http/Headers.vue
Expand Up @@ -619,6 +619,7 @@ const inheritedProperties = computed(() => {
const computedAuthHeader = getComputedAuthHeaders(
aggregateEnvs.value,
request.value,
// AM-COMMENT: check this line, this is because the GqlAuth is not updated yet to use the updated auth type
props.inheritedProperties.auth.inheritedAuth,
false
)[0]
Expand Down

0 comments on commit 0e12233

Please sign in to comment.