Skip to content

Commit

Permalink
🛠️: refactor OAuth2 callback to handle errors and missing credentials…
Browse files Browse the repository at this point in the history
… and show errors in `CreateUserFileSource`

Co-authored-by: David LĂłpez <[email protected]>
  • Loading branch information
itisAliRH and davelopez committed Oct 14, 2024
1 parent 7d2229d commit 7df9f7c
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 6 deletions.
3 changes: 2 additions & 1 deletion client/src/api/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36796,7 +36796,8 @@ export interface operations {
query: {
/** @description Base-64 encoded JSON used to route request within Galaxy. */
state: string;
code: string;
code?: string | null;
error?: string | null;
};
header?: {
/** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts" setup>
import { computed } from "vue";
import { BAlert } from "bootstrap-vue";
import { computed, ref } from "vue";
import { useRouter } from "vue-router/composables";
import { useFileSourceTemplatesStore } from "@/stores/fileSourceTemplatesStore";
Expand All @@ -17,14 +18,37 @@ const loading = computed(() => fileSourceTemplatesStore.loading);
const router = useRouter();
async function chooseTemplate(selectTemplateId: string) {
const errorMessage = ref("");
function chooseTemplate(selectTemplateId: string) {
router.push({
path: `/file_source_templates/${selectTemplateId}/new`,
});
}
function handleOAuth2Redirect() {
if (router.currentRoute.query.error === "access_denied") {
errorMessage.value = "You must authorize Galaxy to access this resource. Please try again.";
} else if (router.currentRoute.query.error) {
const error = router.currentRoute.query.error;
if (Array.isArray(error)) {
errorMessage.value = error[0] || "There was an error creating the file source.";
} else {
errorMessage.value = error;
}
}
}
handleOAuth2Redirect();
</script>

<template>
<CreateInstance :loading-message="loadingTemplatesInfoMessage" :loading="loading" prefix="file-source">
<BAlert v-if="errorMessage" variant="danger" show dismissible>
{{ errorMessage }}
</BAlert>

<SelectTemplate :templates="templates" @onSubmit="chooseTemplate" />
</CreateInstance>
</template>
5 changes: 5 additions & 0 deletions client/src/entry/analysis/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,11 @@ export function getRouter(Galaxy) {
{
path: "file_source_instances/create",
component: CreateUserFileSource,
props: (route) => {
return {
error: route.params.error,
};
},
},
{
path: "file_source_instances/index",
Expand Down
22 changes: 19 additions & 3 deletions lib/galaxy/webapps/galaxy/api/oauth2_callback.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

from fastapi import Query
from fastapi.responses import RedirectResponse

Expand All @@ -16,13 +18,19 @@
title="State information sent with auth request",
description="Base-64 encoded JSON used to route request within Galaxy.",
)
CodeQueryParam: str = Query(
...,
CodeQueryParam: Optional[str] = Query(
None,
title="OAuth2 Authorization Code from remote resource",
)
ErrorQueryParam: Optional[str] = Query(
None,
title="OAuth2 Error from remote resource",
)

router = Router(tags=["oauth2"])

ERROR_REDIRECT_PATH = "file_source_instances/create"


@router.cbv
class OAuth2Callback:
Expand All @@ -36,8 +44,16 @@ def oauth2_callback(
self,
trans: SessionRequestContext = DependsOnTrans,
state: str = StateQueryParam,
code: str = CodeQueryParam,
code: Optional[str] = CodeQueryParam,
error: Optional[str] = ErrorQueryParam,
):
if error:
return RedirectResponse(f"{trans.request.url_path}{ERROR_REDIRECT_PATH}?error={error}")
elif not code:
return RedirectResponse(
f"{trans.request.url_path}{ERROR_REDIRECT_PATH}?error=No credentials provided, please try again."
)

oauth2_state = OAuth2State.decode(state)
# TODO: save session information in cookie to verify not CSRF with oauth2_state.nonce
route = oauth2_state.route
Expand Down

0 comments on commit 7df9f7c

Please sign in to comment.