@scalar/api-client 3.1.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/components/HttpMethod/HttpMethod.vue.d.ts +2 -2
  3. package/dist/components/Sidebar/Actions/SidebarListElementForm.vue.d.ts +2 -2
  4. package/dist/style.css +95 -71
  5. package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
  6. package/dist/v2/blocks/operation-block/OperationBlock.vue.js.map +1 -1
  7. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js +2 -1
  8. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
  9. package/dist/v2/blocks/operation-block/helpers/send-request.d.ts +5 -1
  10. package/dist/v2/blocks/operation-block/helpers/send-request.d.ts.map +1 -1
  11. package/dist/v2/blocks/operation-block/helpers/send-request.js +2 -2
  12. package/dist/v2/blocks/operation-block/helpers/send-request.js.map +1 -1
  13. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.d.ts.map +1 -1
  14. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.js +1 -1
  15. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.js.map +1 -1
  16. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.script.js +4 -0
  17. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.script.js.map +1 -1
  18. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js.map +1 -1
  19. package/dist/v2/blocks/request-block/components/RequestBody.vue.d.ts.map +1 -1
  20. package/dist/v2/blocks/request-block/components/RequestBody.vue.js +1 -1
  21. package/dist/v2/blocks/request-block/components/RequestBody.vue.js.map +1 -1
  22. package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js +1 -0
  23. package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js.map +1 -1
  24. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts.map +1 -1
  25. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.js.map +1 -1
  26. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js +1 -0
  27. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js.map +1 -1
  28. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts +1 -1
  29. package/dist/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue.js.map +1 -1
  30. package/dist/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue.script.js +3 -3
  31. package/dist/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue.script.js.map +1 -1
  32. package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
  33. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.d.ts.map +1 -1
  34. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.js.map +1 -1
  35. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js +131 -48
  36. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js.map +1 -1
  37. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuthScopesAddModal.vue.d.ts +2 -2
  38. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuthScopesAddModal.vue.d.ts.map +1 -1
  39. package/dist/v2/blocks/scalar-auth-selector-block/helpers/extract-security-scheme-secrets.d.ts.map +1 -1
  40. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.d.ts +16 -0
  41. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.d.ts.map +1 -1
  42. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js +43 -1
  43. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js.map +1 -1
  44. package/dist/v2/components/code-input/CodeInput.vue.d.ts +6 -2
  45. package/dist/v2/components/code-input/CodeInput.vue.d.ts.map +1 -1
  46. package/dist/v2/components/code-input/CodeInput.vue.js +1 -1
  47. package/dist/v2/components/code-input/CodeInput.vue.js.map +1 -1
  48. package/dist/v2/components/code-input/CodeInput.vue.script.js +9 -4
  49. package/dist/v2/components/code-input/CodeInput.vue.script.js.map +1 -1
  50. package/dist/v2/components/data-table/DataTableInput.vue.d.ts +3 -0
  51. package/dist/v2/components/data-table/DataTableInput.vue.d.ts.map +1 -1
  52. package/dist/v2/components/data-table/DataTableInput.vue.js +1 -1
  53. package/dist/v2/components/data-table/DataTableInput.vue.js.map +1 -1
  54. package/dist/v2/components/data-table/DataTableInput.vue.script.js +7 -1
  55. package/dist/v2/components/data-table/DataTableInput.vue.script.js.map +1 -1
  56. package/dist/v2/components/forms/ConfirmationForm.vue.d.ts +2 -2
  57. package/dist/v2/components/sidebar/Sidebar.vue.d.ts.map +1 -1
  58. package/dist/v2/components/sidebar/Sidebar.vue.js.map +1 -1
  59. package/dist/v2/components/sidebar/Sidebar.vue.script.js +16 -8
  60. package/dist/v2/components/sidebar/Sidebar.vue.script.js.map +1 -1
  61. package/dist/v2/components/sidebar/SidebarToggle.vue.js.map +1 -1
  62. package/dist/v2/components/sidebar/SidebarToggle.vue.script.js +1 -1
  63. package/dist/v2/components/sidebar/SidebarToggle.vue.script.js.map +1 -1
  64. package/dist/v2/constants.js +1 -1
  65. package/dist/v2/features/app/App.vue.d.ts.map +1 -1
  66. package/dist/v2/features/app/App.vue.js.map +1 -1
  67. package/dist/v2/features/app/App.vue.script.js +13 -13
  68. package/dist/v2/features/app/App.vue.script.js.map +1 -1
  69. package/dist/v2/features/app/app-state.d.ts +6 -1
  70. package/dist/v2/features/app/app-state.d.ts.map +1 -1
  71. package/dist/v2/features/app/app-state.js +5 -3
  72. package/dist/v2/features/app/app-state.js.map +1 -1
  73. package/dist/v2/features/app/components/AppSidebar.vue.js +1 -1
  74. package/dist/v2/features/app/components/AppSidebar.vue.js.map +1 -1
  75. package/dist/v2/features/app/components/AppSidebar.vue.script.js +1 -1
  76. package/dist/v2/features/app/components/AppSidebar.vue.script.js.map +1 -1
  77. package/dist/v2/features/app/components/DesktopTab.vue.d.ts +2 -2
  78. package/dist/v2/features/app/helpers/create-api-client-app.d.ts +9 -1
  79. package/dist/v2/features/app/helpers/create-api-client-app.d.ts.map +1 -1
  80. package/dist/v2/features/app/helpers/create-api-client-app.js +3 -2
  81. package/dist/v2/features/app/helpers/create-api-client-app.js.map +1 -1
  82. package/dist/v2/features/app/helpers/routes.d.ts +4 -2
  83. package/dist/v2/features/app/helpers/routes.d.ts.map +1 -1
  84. package/dist/v2/features/app/helpers/routes.js.map +1 -1
  85. package/dist/v2/features/collection/DocumentCollection.vue.script.js +2 -1
  86. package/dist/v2/features/collection/DocumentCollection.vue.script.js.map +1 -1
  87. package/dist/v2/features/collection/OperationCollection.vue.script.js +2 -1
  88. package/dist/v2/features/collection/OperationCollection.vue.script.js.map +1 -1
  89. package/dist/v2/features/collection/WorkspaceCollection.vue.script.js +2 -1
  90. package/dist/v2/features/collection/WorkspaceCollection.vue.script.js.map +1 -1
  91. package/dist/v2/features/collection/components/Authentication.vue.d.ts.map +1 -1
  92. package/dist/v2/features/collection/components/Authentication.vue.js +1 -1
  93. package/dist/v2/features/collection/components/Authentication.vue.js.map +1 -1
  94. package/dist/v2/features/collection/components/Authentication.vue.script.js +10 -1
  95. package/dist/v2/features/collection/components/Authentication.vue.script.js.map +1 -1
  96. package/dist/v2/features/collection/components/Cookies.vue.script.js +1 -0
  97. package/dist/v2/features/collection/components/Cookies.vue.script.js.map +1 -1
  98. package/dist/v2/features/collection/components/Editor/Editor.vue.script.js +1 -0
  99. package/dist/v2/features/collection/components/Editor/Editor.vue.script.js.map +1 -1
  100. package/dist/v2/features/collection/components/Environment.vue.script.js +1 -0
  101. package/dist/v2/features/collection/components/Environment.vue.script.js.map +1 -1
  102. package/dist/v2/features/collection/components/Form.vue.d.ts +2 -0
  103. package/dist/v2/features/collection/components/Form.vue.d.ts.map +1 -1
  104. package/dist/v2/features/collection/components/Form.vue.js.map +1 -1
  105. package/dist/v2/features/collection/components/Form.vue.script.js +4 -1
  106. package/dist/v2/features/collection/components/Form.vue.script.js.map +1 -1
  107. package/dist/v2/features/collection/components/LabelInput.vue.d.ts +1 -1
  108. package/dist/v2/features/collection/components/Overview.vue.script.js +1 -0
  109. package/dist/v2/features/collection/components/Overview.vue.script.js.map +1 -1
  110. package/dist/v2/features/collection/components/Runner/components/Runner.vue.d.ts.map +1 -1
  111. package/dist/v2/features/collection/components/Runner/components/Runner.vue.js.map +1 -1
  112. package/dist/v2/features/collection/components/Runner/components/Runner.vue.script.js +4 -2
  113. package/dist/v2/features/collection/components/Runner/components/Runner.vue.script.js.map +1 -1
  114. package/dist/v2/features/collection/components/Runner/components/RunnerTree.vue.d.ts +2 -2
  115. package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.d.ts +4 -2
  116. package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.d.ts.map +1 -1
  117. package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.js +3 -2
  118. package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.js.map +1 -1
  119. package/dist/v2/features/collection/components/Scripts.vue.script.js +1 -0
  120. package/dist/v2/features/collection/components/Scripts.vue.script.js.map +1 -1
  121. package/dist/v2/features/collection/components/Servers.vue.d.ts.map +1 -1
  122. package/dist/v2/features/collection/components/Servers.vue.js.map +1 -1
  123. package/dist/v2/features/collection/components/Servers.vue.script.js +3 -1
  124. package/dist/v2/features/collection/components/Servers.vue.script.js.map +1 -1
  125. package/dist/v2/features/collection/components/Settings.vue.script.js +1 -0
  126. package/dist/v2/features/collection/components/Settings.vue.script.js.map +1 -1
  127. package/dist/v2/features/command-palette/components/CommandActionForm.vue.d.ts +2 -2
  128. package/dist/v2/features/environments/components/EnvironmentDeleteModal.vue.d.ts +2 -2
  129. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.d.ts +1 -1
  130. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.d.ts.map +1 -1
  131. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.js.map +1 -1
  132. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.script.js +2 -2
  133. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.script.js.map +1 -1
  134. package/dist/v2/features/global-cookies/components/CookiesTable.vue.d.ts.map +1 -1
  135. package/dist/v2/features/global-cookies/components/CookiesTable.vue.js +1 -1
  136. package/dist/v2/features/global-cookies/components/CookiesTable.vue.js.map +1 -1
  137. package/dist/v2/features/global-cookies/components/CookiesTable.vue.script.js +2 -0
  138. package/dist/v2/features/global-cookies/components/CookiesTable.vue.script.js.map +1 -1
  139. package/dist/v2/features/modal/Modal.vue.d.ts +7 -6
  140. package/dist/v2/features/modal/Modal.vue.d.ts.map +1 -1
  141. package/dist/v2/features/modal/Modal.vue.js.map +1 -1
  142. package/dist/v2/features/modal/Modal.vue.script.js +2 -2
  143. package/dist/v2/features/modal/Modal.vue.script.js.map +1 -1
  144. package/dist/v2/features/modal/helpers/create-api-client-modal.d.ts +5 -5
  145. package/dist/v2/features/modal/helpers/create-api-client-modal.d.ts.map +1 -1
  146. package/dist/v2/features/modal/helpers/create-api-client-modal.js.map +1 -1
  147. package/dist/v2/features/modal/helpers/types.d.ts +1 -7
  148. package/dist/v2/features/modal/helpers/types.d.ts.map +1 -1
  149. package/dist/v2/features/modal/index.d.ts +1 -1
  150. package/dist/v2/features/modal/index.d.ts.map +1 -1
  151. package/dist/v2/features/operation/Operation.vue.d.ts +0 -5
  152. package/dist/v2/features/operation/Operation.vue.d.ts.map +1 -1
  153. package/dist/v2/features/operation/Operation.vue.js.map +1 -1
  154. package/dist/v2/features/operation/Operation.vue.script.js.map +1 -1
  155. package/dist/v2/types/options.d.ts +15 -0
  156. package/dist/v2/types/options.d.ts.map +1 -0
  157. package/package.json +13 -13
@@ -1 +1 @@
1
- {"version":3,"file":"OAuth2.vue.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Any config options required for the OAuth2 flow */\nexport type OAuth2Options = Pick<ApiClientConfiguration, 'oauth2RedirectUri'>\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton, useLoadingState } from '@scalar/components'\nimport type { ApiClientConfiguration } from '@scalar/types/api-reference'\nimport { pkceOptions } from '@scalar/types/entities'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { SecretsOAuthFlows } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n getEnvironmentVariables,\n type OAuthFlowAuthorizationCodeSecret,\n type OAuthFlowClientCredentialsSecret,\n type OAuthFlowPasswordSecret,\n type OAuthFlowsObjectSecret,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCredentialsLocation } from '@scalar/workspace-store/schemas/extensions/security/x-scalar-credentials-location'\nimport { type XusePkce } from '@scalar/workspace-store/schemas/extensions/security/x-use-pkce'\nimport type {\n OAuthFlow,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport OAuthScopesInput from '@/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue'\nimport { authorizeOauth2 } from '@/v2/blocks/scalar-auth-selector-block/helpers/oauth'\nimport { resolveDefaultOAuth2RedirectUri } from '@/v2/blocks/scalar-auth-selector-block/helpers/resolve-default-oauth2-redirect-url'\nimport { DataTableRow } from '@/v2/components/data-table'\n\nimport RequestAuthDataTableInput from './RequestAuthDataTableInput.vue'\n\nconst {\n environment,\n flows,\n type,\n scheme,\n selectedScopes: selectedScopesProp,\n server,\n proxyUrl,\n eventBus,\n name,\n options = {},\n} = defineProps<{\n /** Current environment configuration */\n environment: XScalarEnvironment\n /** OAuth flows */\n flows: OAuthFlowsObjectSecret\n /** Type of the OAuth flow */\n type: keyof OAuthFlowsObjectSecret\n /** Selected scopes */\n selectedScopes: string[]\n /** Security scheme */\n scheme: SecuritySchemeObjectSecret\n /** Current server configuration */\n server: ServerObject | null\n /** Proxy URL */\n proxyUrl: string\n /** Name of the security scheme */\n name: string\n /** Event bus for authentication updates */\n eventBus: WorkspaceEventBus\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst emits = defineEmits<{\n (\n e: 'update:selectedScopes',\n payload: Pick<\n ApiReferenceEvents['auth:update:selected-scopes'],\n 'scopes' | 'newScopePayload'\n >,\n ): void\n}>()\n\nconst loader = useLoadingState()\nconst { toast } = useToasts()\n\n/** The current OAuth flow based on the selected type */\nconst flow = computed(() => flows[type]!)\ntype NonImplicitFlow =\n | OAuthFlowPasswordSecret\n | OAuthFlowClientCredentialsSecret\n | OAuthFlowAuthorizationCodeSecret\n\n/** We filter selected scopes to only include scopes that are in this flow*/\nconst selectedScopes = computed(() =>\n selectedScopesProp.filter((scope) => scope in (flow.value.scopes ?? {})),\n)\n\n/** Updates the security scheme base */\nconst handleOauth2Update = (\n payload: Partial<OAuthFlow & XScalarCredentialsLocation>,\n): void => {\n // OpenIdConnect uses the secrets update for all\n if (scheme.type === 'openIdConnect') {\n return handleOauth2SecretsUpdate(payload)\n }\n\n eventBus.emit('auth:update:security-scheme', {\n payload: {\n type: scheme.type,\n flows: {\n [type]: payload,\n },\n },\n name,\n })\n}\n\n/** Updates the flow secrets */\nconst handleOauth2SecretsUpdate = (\n payload: Omit<Partial<SecretsOAuthFlows[keyof SecretsOAuthFlows]>, 'type'>,\n): void =>\n eventBus.emit('auth:update:security-scheme-secrets', {\n payload: {\n type: scheme.type,\n [type]: payload,\n },\n name,\n })\n\n/** Clears the flow secrets */\nconst clearOauth2Secrets = (): void =>\n eventBus.emit('auth:clear:security-scheme-secrets', {\n name,\n })\n\n/** Track if we have set the redirect uri */\nconst hasPrefilledRedirectUri = ref(false)\n\n/** Default the redirect-uri to the current origin if we have access to window */\nwatch(\n () =>\n (flow.value as OAuthFlowAuthorizationCodeSecret)[\n 'x-scalar-secret-redirect-uri'\n ],\n (newRedirectUri) => {\n const defaultRedirectUri = resolveDefaultOAuth2RedirectUri(options)\n\n if (\n hasPrefilledRedirectUri.value ||\n newRedirectUri ||\n !defaultRedirectUri ||\n !('x-scalar-secret-redirect-uri' in flow.value)\n ) {\n return\n }\n hasPrefilledRedirectUri.value = true\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-redirect-uri': defaultRedirectUri,\n })\n },\n { immediate: true },\n)\n\n/**\n * Authorizes the user using the specified OAuth flow.\n * Opens the appropriate OAuth dialog and/or performs the token exchange.\n */\nconst handleAuthorize = async (): Promise<void> => {\n if (loader.isLoading) {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await authorizeOauth2(\n flows,\n type,\n selectedScopes.value,\n server,\n proxyUrl,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to authorize', 'error')\n }\n}\n\n/** Updates the secret location */\nconst handleSecretLocationUpdate = (value: string): void => {\n const credentialsLocation = value === 'body' ? 'body' : 'header'\n\n if (scheme.type !== 'openIdConnect') {\n handleOauth2Update({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n}\n</script>\n\n<template>\n <!-- Access Token Display: Shows when user is already authorized -->\n <template v-if=\"Boolean(flow['x-scalar-secret-token'])\">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token']\"\n placeholder=\"QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-token': v })\n \">\n Access Token\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 items-center justify-end gap-2 border-t\">\n <ScalarButton\n class=\"mr-1 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': '',\n 'x-scalar-secret-refresh-token': '',\n })\n \">\n Clear\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n\n <!-- Authorization Form: Shows when user needs to authorize -->\n <template v-else>\n <DataTableRow>\n <RequestAuthDataTableInput\n v-if=\"'authorizationUrl' in flow\"\n containerClass=\"border-r-0\"\n :environment\n :modelValue=\"flow['x-scalar-secret-auth-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/authorize\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-auth-url': v })\n handleOauth2Update({ authorizationUrl: v })\n }\n \">\n Auth URL\n </RequestAuthDataTableInput>\n\n <RequestAuthDataTableInput\n v-if=\"'tokenUrl' in flow\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/token\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-token-url': v })\n handleOauth2Update({ tokenUrl: v })\n }\n \">\n Token URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-redirect-uri' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-redirect-uri']\"\n placeholder=\"https://galaxy.scalar.com/callback\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-redirect-uri': v })\n }\n \">\n Redirect URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <template\n v-if=\"\n 'x-scalar-secret-username' in flow && 'x-scalar-secret-password' in flow\n \">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"text-c-2\"\n :environment\n :modelValue=\"flow['x-scalar-secret-username']\"\n placeholder=\"janedoe\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-username': v })\n \">\n Username\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-password']\"\n placeholder=\"********\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-password': v })\n \">\n Password\n </RequestAuthDataTableInput>\n </DataTableRow>\n </template>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-id']\"\n placeholder=\"12345\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-client-id': v })\n \">\n Client ID\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-client-secret' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-secret']\"\n placeholder=\"XYZ123\"\n type=\"password\"\n @update:modelValue=\"\n (v) =>\n handleOauth2SecretsUpdate({ 'x-scalar-secret-client-secret': v })\n \">\n Client Secret\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-usePkce' in flow\">\n <RequestAuthDataTableInput\n :enum=\"pkceOptions\"\n :environment\n :modelValue=\"flow['x-usePkce']\"\n readOnly\n @update:modelValue=\"\n (v) =>\n handleOauth2Update({\n 'x-usePkce': v as XusePkce['x-usePkce'],\n })\n \">\n Use PKCE\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Credentials Location -->\n <DataTableRow v-if=\"type !== 'implicit'\">\n <RequestAuthDataTableInput\n :enum=\"['header', 'body']\"\n :environment\n :modelValue=\"\n (flow as NonImplicitFlow)['x-scalar-credentials-location'] || 'header'\n \"\n placeholder=\"header\"\n readOnly\n @update:modelValue=\"(v) => handleSecretLocationUpdate(v)\">\n Credentials Location\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Scopes -->\n <DataTableRow>\n <OAuthScopesInput\n :flow\n :flowType=\"type\"\n :selectedScopes\n @update:selectedScopes=\"(v) => emits('update:selectedScopes', v)\" />\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 w-full items-center justify-end border-t\">\n <!-- Allow clearing the oauth section and going back to discovery -->\n <ScalarButton\n v-if=\"scheme.type === 'openIdConnect'\"\n class=\"mr-1 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"clearOauth2Secrets\">\n Clear\n </ScalarButton>\n\n <ScalarButton\n class=\"mr-0.75 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleAuthorize\">\n Authorize\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"OAuth2.vue.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Any config options required for the OAuth2 flow */\nexport type OAuth2Options = Pick<ApiClientConfiguration, 'oauth2RedirectUri'>\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton, useLoadingState } from '@scalar/components'\nimport type { ApiClientConfiguration } from '@scalar/types/api-reference'\nimport { pkceOptions } from '@scalar/types/entities'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { SecretsOAuthFlows } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n getEnvironmentVariables,\n type OAuthFlowAuthorizationCodeSecret,\n type OAuthFlowClientCredentialsSecret,\n type OAuthFlowPasswordSecret,\n type OAuthFlowsObjectSecret,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCredentialsLocation } from '@scalar/workspace-store/schemas/extensions/security/x-scalar-credentials-location'\nimport { type XusePkce } from '@scalar/workspace-store/schemas/extensions/security/x-use-pkce'\nimport type {\n OAuthFlow,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport OAuthScopesInput from '@/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue'\nimport {\n authorizeOauth2,\n refreshOauth2Token,\n} from '@/v2/blocks/scalar-auth-selector-block/helpers/oauth'\nimport { resolveDefaultOAuth2RedirectUri } from '@/v2/blocks/scalar-auth-selector-block/helpers/resolve-default-oauth2-redirect-url'\nimport { DataTableRow } from '@/v2/components/data-table'\n\nimport RequestAuthDataTableInput from './RequestAuthDataTableInput.vue'\n\nconst {\n environment,\n flows,\n type,\n scheme,\n selectedScopes: selectedScopesProp,\n server,\n proxyUrl,\n eventBus,\n name,\n options = {},\n} = defineProps<{\n /** Current environment configuration */\n environment: XScalarEnvironment\n /** OAuth flows */\n flows: OAuthFlowsObjectSecret\n /** Type of the OAuth flow */\n type: keyof OAuthFlowsObjectSecret\n /** Selected scopes */\n selectedScopes: string[]\n /** Security scheme */\n scheme: SecuritySchemeObjectSecret\n /** Current server configuration */\n server: ServerObject | null\n /** Proxy URL */\n proxyUrl: string\n /** Name of the security scheme */\n name: string\n /** Event bus for authentication updates */\n eventBus: WorkspaceEventBus\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst emits = defineEmits<{\n (\n e: 'update:selectedScopes',\n payload: Pick<\n ApiReferenceEvents['auth:update:selected-scopes'],\n 'scopes' | 'newScopePayload'\n >,\n ): void\n}>()\n\nconst loader = useLoadingState()\nconst { toast } = useToasts()\n\n/** The current OAuth flow based on the selected type */\nconst flow = computed(() => flows[type]!)\ntype NonImplicitFlow =\n | OAuthFlowPasswordSecret\n | OAuthFlowClientCredentialsSecret\n | OAuthFlowAuthorizationCodeSecret\n\n/** We filter selected scopes to only include scopes that are in this flow*/\nconst selectedScopes = computed(() =>\n selectedScopesProp.filter((scope) => scope in (flow.value.scopes ?? {})),\n)\n\n/** Updates the security scheme base */\nconst handleOauth2Update = (\n payload: Partial<OAuthFlow & XScalarCredentialsLocation>,\n): void => {\n // OpenIdConnect uses the secrets update for all\n if (scheme.type === 'openIdConnect') {\n return handleOauth2SecretsUpdate(payload)\n }\n\n eventBus.emit('auth:update:security-scheme', {\n payload: {\n type: scheme.type,\n flows: {\n [type]: payload,\n },\n },\n name,\n })\n}\n\n/** Updates the flow secrets */\nconst handleOauth2SecretsUpdate = (\n payload: Omit<Partial<SecretsOAuthFlows[keyof SecretsOAuthFlows]>, 'type'>,\n): void =>\n eventBus.emit('auth:update:security-scheme-secrets', {\n payload: {\n type: scheme.type,\n [type]: payload,\n },\n name,\n })\n\n/** Clears the flow secrets */\nconst clearOauth2Secrets = (): void => {\n if (loader.isLoading) {\n return\n }\n eventBus.emit('auth:clear:security-scheme-secrets', {\n name,\n })\n}\n\n/** Clears stored access and refresh tokens (authorized state) */\nconst handleClearAccessTokens = (): void => {\n if (loader.isLoading) {\n return\n }\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': '',\n 'x-scalar-secret-refresh-token': '',\n })\n}\n\n/** Track redirect URI prefill per flow instance to support document switching */\nconst prefilledFlowIdentity = ref<string | null>(null)\nconst hasHandledRedirectPrefill = ref(false)\n\nconst resolveFlowIdentity = (\n currentFlow: OAuthFlowsObjectSecret[keyof OAuthFlowsObjectSecret] | undefined,\n): string =>\n JSON.stringify({\n type,\n authorizationUrl:\n currentFlow && 'authorizationUrl' in currentFlow\n ? currentFlow.authorizationUrl\n : '',\n tokenUrl:\n currentFlow && 'tokenUrl' in currentFlow ? currentFlow.tokenUrl : '',\n refreshUrl: currentFlow?.refreshUrl ?? '',\n scopes: Object.keys(currentFlow?.scopes ?? {}),\n })\n\n/** Default the redirect-uri to the current origin if we have access to window */\nwatch(\n () => flow.value,\n (currentFlow) => {\n if (!currentFlow || !('x-scalar-secret-redirect-uri' in currentFlow)) {\n return\n }\n\n const flowIdentity = resolveFlowIdentity(currentFlow)\n if (prefilledFlowIdentity.value !== flowIdentity) {\n prefilledFlowIdentity.value = flowIdentity\n hasHandledRedirectPrefill.value = false\n }\n\n if (hasHandledRedirectPrefill.value) {\n return\n }\n\n const newRedirectUri = (currentFlow as OAuthFlowAuthorizationCodeSecret)[\n 'x-scalar-secret-redirect-uri'\n ]\n const defaultRedirectUri = resolveDefaultOAuth2RedirectUri(options)\n\n hasHandledRedirectPrefill.value = true\n\n if (newRedirectUri || !defaultRedirectUri) {\n return\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-redirect-uri': defaultRedirectUri,\n })\n },\n { immediate: true },\n)\n\n/**\n * Authorizes the user using the specified OAuth flow.\n * Opens the appropriate OAuth dialog and/or performs the token exchange.\n */\nconst handleAuthorize = async (): Promise<void> => {\n if (loader.isLoading) {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await authorizeOauth2(\n flows,\n type,\n selectedScopes.value,\n server,\n proxyUrl,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to authorize', 'error')\n }\n}\n\n/** Whether the current flow supports refreshing the access token */\nconst supportsRefreshToken = computed(() => type !== 'implicit')\n\n/**\n * Refresh URL placeholder, shows tokenUrl as hint if refreshUrl is not specified.\n * This helps users understand that tokenUrl will be used as fallback.\n */\nconst refreshUrlPlaceholder = computed(() => {\n if ('tokenUrl' in flow.value && flow.value.tokenUrl) {\n return flow.value.tokenUrl\n }\n return 'https://galaxy.scalar.com/oauth/refresh'\n})\n\n/**\n * Uses the stored refresh token to obtain a new access token\n * via grant_type=refresh_token.\n */\nconst handleRefresh = async (): Promise<void> => {\n if (loader.isLoading || type === 'implicit') {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await refreshOauth2Token(\n flows,\n type,\n proxyUrl,\n server,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to refresh token', 'error')\n }\n}\n\n/** Updates the secret location */\nconst handleSecretLocationUpdate = (value: string): void => {\n const credentialsLocation = value === 'body' ? 'body' : 'header'\n\n if (scheme.type !== 'openIdConnect') {\n handleOauth2Update({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n}\n</script>\n\n<template>\n <!-- Access Token Display: Shows when user is already authorized -->\n <template v-if=\"Boolean(flow['x-scalar-secret-token'])\">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token']\"\n placeholder=\"QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-token': v })\n \">\n Access Token\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"supportsRefreshToken\">\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow.refreshUrl ?? ''\"\n :placeholder=\"refreshUrlPlaceholder\"\n @update:modelValue=\"(v) => handleOauth2Update({ refreshUrl: v })\">\n Refresh URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 items-center justify-end gap-2 border-t\">\n <ScalarButton\n v-if=\"supportsRefreshToken\"\n class=\"p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleRefresh\">\n Refresh\n </ScalarButton>\n <ScalarButton\n class=\"mr-1 p-0 px-2 py-0.5\"\n :disabled=\"loader.isLoading\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleClearAccessTokens\">\n Clear\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n\n <!-- Authorization Form: Shows when user needs to authorize -->\n <template v-else>\n <DataTableRow>\n <RequestAuthDataTableInput\n v-if=\"'authorizationUrl' in flow\"\n containerClass=\"border-r-0\"\n :environment\n :modelValue=\"flow['x-scalar-secret-auth-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/authorize\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-auth-url': v })\n handleOauth2Update({ authorizationUrl: v })\n }\n \">\n Auth URL\n </RequestAuthDataTableInput>\n\n <RequestAuthDataTableInput\n v-if=\"'tokenUrl' in flow\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/token\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-token-url': v })\n handleOauth2Update({ tokenUrl: v })\n }\n \">\n Token URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-redirect-uri' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-redirect-uri']\"\n placeholder=\"Optional redirect URL\"\n @update:modelValue=\"\n (v) => {\n hasHandledRedirectPrefill = true\n handleOauth2SecretsUpdate({ 'x-scalar-secret-redirect-uri': v })\n }\n \">\n Redirect URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <template\n v-if=\"\n 'x-scalar-secret-username' in flow && 'x-scalar-secret-password' in flow\n \">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"text-c-2\"\n :environment\n :modelValue=\"flow['x-scalar-secret-username']\"\n placeholder=\"janedoe\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-username': v })\n \">\n Username\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-password']\"\n placeholder=\"********\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-password': v })\n \">\n Password\n </RequestAuthDataTableInput>\n </DataTableRow>\n </template>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-id']\"\n placeholder=\"12345\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-client-id': v })\n \">\n Client ID\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-client-secret' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-secret']\"\n placeholder=\"XYZ123\"\n type=\"password\"\n @update:modelValue=\"\n (v) =>\n handleOauth2SecretsUpdate({ 'x-scalar-secret-client-secret': v })\n \">\n Client Secret\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-usePkce' in flow\">\n <RequestAuthDataTableInput\n :enum=\"pkceOptions\"\n :environment\n :modelValue=\"flow['x-usePkce']\"\n readOnly\n @update:modelValue=\"\n (v) =>\n handleOauth2Update({\n 'x-usePkce': v as XusePkce['x-usePkce'],\n })\n \">\n Use PKCE\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Credentials Location -->\n <DataTableRow v-if=\"type !== 'implicit'\">\n <RequestAuthDataTableInput\n :enum=\"['header', 'body']\"\n :environment\n :modelValue=\"\n (flow as NonImplicitFlow)['x-scalar-credentials-location'] || 'header'\n \"\n placeholder=\"header\"\n readOnly\n @update:modelValue=\"(v) => handleSecretLocationUpdate(v)\">\n Credentials Location\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Scopes -->\n <DataTableRow>\n <OAuthScopesInput\n :flow\n :flowType=\"type\"\n :selectedScopes\n @update:selectedScopes=\"(v) => emits('update:selectedScopes', v)\" />\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 w-full items-center justify-end border-t\">\n <!-- Allow clearing the oauth section and going back to discovery -->\n <ScalarButton\n v-if=\"scheme.type === 'openIdConnect'\"\n class=\"mr-1 p-0 px-2 py-0.5\"\n :disabled=\"loader.isLoading\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"clearOauth2Secrets\">\n Clear\n </ScalarButton>\n\n <ScalarButton\n class=\"mr-0.75 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleAuthorize\">\n Authorize\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n</template>\n"],"mappings":""}
@@ -1,6 +1,6 @@
1
1
  import DataTableRow_default from "../../../components/data-table/DataTableRow.vue.js";
2
2
  import OAuthScopesInput_default from "./OAuthScopesInput.vue.js";
3
- import { authorizeOauth2 } from "../helpers/oauth.js";
3
+ import { authorizeOauth2, refreshOauth2Token } from "../helpers/oauth.js";
4
4
  import { resolveDefaultOAuth2RedirectUri } from "../helpers/resolve-default-oauth2-redirect-url.js";
5
5
  import RequestAuthDataTableInput_default from "./RequestAuthDataTableInput.vue.js";
6
6
  import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, openBlock, ref, unref, watch, withCtx } from "vue";
@@ -53,14 +53,41 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
53
53
  name: __props.name
54
54
  });
55
55
  /** Clears the flow secrets */
56
- const clearOauth2Secrets = () => __props.eventBus.emit("auth:clear:security-scheme-secrets", { name: __props.name });
57
- /** Track if we have set the redirect uri */
58
- const hasPrefilledRedirectUri = ref(false);
56
+ const clearOauth2Secrets = () => {
57
+ if (loader.isLoading) return;
58
+ __props.eventBus.emit("auth:clear:security-scheme-secrets", { name: __props.name });
59
+ };
60
+ /** Clears stored access and refresh tokens (authorized state) */
61
+ const handleClearAccessTokens = () => {
62
+ if (loader.isLoading) return;
63
+ handleOauth2SecretsUpdate({
64
+ "x-scalar-secret-token": "",
65
+ "x-scalar-secret-refresh-token": ""
66
+ });
67
+ };
68
+ /** Track redirect URI prefill per flow instance to support document switching */
69
+ const prefilledFlowIdentity = ref(null);
70
+ const hasHandledRedirectPrefill = ref(false);
71
+ const resolveFlowIdentity = (currentFlow) => JSON.stringify({
72
+ type: __props.type,
73
+ authorizationUrl: currentFlow && "authorizationUrl" in currentFlow ? currentFlow.authorizationUrl : "",
74
+ tokenUrl: currentFlow && "tokenUrl" in currentFlow ? currentFlow.tokenUrl : "",
75
+ refreshUrl: currentFlow?.refreshUrl ?? "",
76
+ scopes: Object.keys(currentFlow?.scopes ?? {})
77
+ });
59
78
  /** Default the redirect-uri to the current origin if we have access to window */
60
- watch(() => flow.value["x-scalar-secret-redirect-uri"], (newRedirectUri) => {
79
+ watch(() => flow.value, (currentFlow) => {
80
+ if (!currentFlow || !("x-scalar-secret-redirect-uri" in currentFlow)) return;
81
+ const flowIdentity = resolveFlowIdentity(currentFlow);
82
+ if (prefilledFlowIdentity.value !== flowIdentity) {
83
+ prefilledFlowIdentity.value = flowIdentity;
84
+ hasHandledRedirectPrefill.value = false;
85
+ }
86
+ if (hasHandledRedirectPrefill.value) return;
87
+ const newRedirectUri = currentFlow["x-scalar-secret-redirect-uri"];
61
88
  const defaultRedirectUri = resolveDefaultOAuth2RedirectUri(__props.options);
62
- if (hasPrefilledRedirectUri.value || newRedirectUri || !defaultRedirectUri || !("x-scalar-secret-redirect-uri" in flow.value)) return;
63
- hasPrefilledRedirectUri.value = true;
89
+ hasHandledRedirectPrefill.value = true;
90
+ if (newRedirectUri || !defaultRedirectUri) return;
64
91
  handleOauth2SecretsUpdate({ "x-scalar-secret-redirect-uri": defaultRedirectUri });
65
92
  }, { immediate: true });
66
93
  /**
@@ -81,6 +108,34 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
81
108
  toast(error?.message ?? "Failed to authorize", "error");
82
109
  }
83
110
  };
111
+ /** Whether the current flow supports refreshing the access token */
112
+ const supportsRefreshToken = computed(() => __props.type !== "implicit");
113
+ /**
114
+ * Refresh URL placeholder, shows tokenUrl as hint if refreshUrl is not specified.
115
+ * This helps users understand that tokenUrl will be used as fallback.
116
+ */
117
+ const refreshUrlPlaceholder = computed(() => {
118
+ if ("tokenUrl" in flow.value && flow.value.tokenUrl) return flow.value.tokenUrl;
119
+ return "https://galaxy.scalar.com/oauth/refresh";
120
+ });
121
+ /**
122
+ * Uses the stored refresh token to obtain a new access token
123
+ * via grant_type=refresh_token.
124
+ */
125
+ const handleRefresh = async () => {
126
+ if (loader.isLoading || __props.type === "implicit") return;
127
+ loader.start();
128
+ const [error, tokens] = await refreshOauth2Token(__props.flows, __props.type, __props.proxyUrl, __props.server, getEnvironmentVariables(__props.environment));
129
+ await loader.clear();
130
+ if (tokens?.accessToken) handleOauth2SecretsUpdate({
131
+ "x-scalar-secret-token": tokens.accessToken,
132
+ ...tokens.refreshToken ? { "x-scalar-secret-refresh-token": tokens.refreshToken } : {}
133
+ });
134
+ else {
135
+ console.error(error);
136
+ toast(error?.message ?? "Failed to refresh token", "error");
137
+ }
138
+ };
84
139
  /** Updates the secret location */
85
140
  const handleSecretLocationUpdate = (value) => {
86
141
  const credentialsLocation = value === "body" ? "body" : "header";
@@ -88,35 +143,62 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
88
143
  handleOauth2SecretsUpdate({ "x-scalar-credentials-location": credentialsLocation });
89
144
  };
90
145
  return (_ctx, _cache) => {
91
- return Boolean(flow.value["x-scalar-secret-token"]) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createVNode(unref(DataTableRow_default), null, {
92
- default: withCtx(() => [createVNode(RequestAuthDataTableInput_default, {
93
- class: "border-r-transparent",
94
- environment: __props.environment,
95
- modelValue: flow.value["x-scalar-secret-token"],
96
- placeholder: "QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT",
97
- type: "password",
98
- "onUpdate:modelValue": _cache[0] || (_cache[0] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-token": v }))
99
- }, {
100
- default: withCtx(() => [..._cache[12] || (_cache[12] = [createTextVNode(" Access Token ", -1)])]),
146
+ return Boolean(flow.value["x-scalar-secret-token"]) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
147
+ createVNode(unref(DataTableRow_default), null, {
148
+ default: withCtx(() => [createVNode(RequestAuthDataTableInput_default, {
149
+ class: "border-r-transparent",
150
+ environment: __props.environment,
151
+ modelValue: flow.value["x-scalar-secret-token"],
152
+ placeholder: "QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT",
153
+ type: "password",
154
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-token": v }))
155
+ }, {
156
+ default: withCtx(() => [..._cache[12] || (_cache[12] = [createTextVNode(" Access Token ", -1)])]),
157
+ _: 1
158
+ }, 8, ["environment", "modelValue"])]),
101
159
  _: 1
102
- }, 8, ["environment", "modelValue"])]),
103
- _: 1
104
- }), createVNode(unref(DataTableRow_default), { class: "min-w-full" }, {
105
- default: withCtx(() => [createElementVNode("div", _hoisted_1, [createVNode(unref(ScalarButton), {
106
- class: "mr-1 p-0 px-2 py-0.5",
107
- loader: unref(loader),
108
- size: "sm",
109
- variant: "outlined",
110
- onClick: _cache[1] || (_cache[1] = () => handleOauth2SecretsUpdate({
111
- "x-scalar-secret-token": "",
112
- "x-scalar-secret-refresh-token": ""
113
- }))
114
- }, {
115
- default: withCtx(() => [..._cache[13] || (_cache[13] = [createTextVNode(" Clear ", -1)])]),
160
+ }),
161
+ supportsRefreshToken.value ? (openBlock(), createBlock(unref(DataTableRow_default), { key: 0 }, {
162
+ default: withCtx(() => [createVNode(RequestAuthDataTableInput_default, {
163
+ class: "border-r-transparent",
164
+ environment: __props.environment,
165
+ modelValue: flow.value.refreshUrl ?? "",
166
+ placeholder: refreshUrlPlaceholder.value,
167
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = (v) => handleOauth2Update({ refreshUrl: v }))
168
+ }, {
169
+ default: withCtx(() => [..._cache[13] || (_cache[13] = [createTextVNode(" Refresh URL ", -1)])]),
170
+ _: 1
171
+ }, 8, [
172
+ "environment",
173
+ "modelValue",
174
+ "placeholder"
175
+ ])]),
116
176
  _: 1
117
- }, 8, ["loader"])])]),
118
- _: 1
119
- })], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
177
+ })) : createCommentVNode("", true),
178
+ createVNode(unref(DataTableRow_default), { class: "min-w-full" }, {
179
+ default: withCtx(() => [createElementVNode("div", _hoisted_1, [supportsRefreshToken.value ? (openBlock(), createBlock(unref(ScalarButton), {
180
+ key: 0,
181
+ class: "p-0 px-2 py-0.5",
182
+ loader: unref(loader),
183
+ size: "sm",
184
+ variant: "outlined",
185
+ onClick: handleRefresh
186
+ }, {
187
+ default: withCtx(() => [..._cache[14] || (_cache[14] = [createTextVNode(" Refresh ", -1)])]),
188
+ _: 1
189
+ }, 8, ["loader"])) : createCommentVNode("", true), createVNode(unref(ScalarButton), {
190
+ class: "mr-1 p-0 px-2 py-0.5",
191
+ disabled: unref(loader).isLoading,
192
+ size: "sm",
193
+ variant: "outlined",
194
+ onClick: handleClearAccessTokens
195
+ }, {
196
+ default: withCtx(() => [..._cache[15] || (_cache[15] = [createTextVNode(" Clear ", -1)])]),
197
+ _: 1
198
+ }, 8, ["disabled"])])]),
199
+ _: 1
200
+ })
201
+ ], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
120
202
  createVNode(unref(DataTableRow_default), null, {
121
203
  default: withCtx(() => ["authorizationUrl" in flow.value ? (openBlock(), createBlock(RequestAuthDataTableInput_default, {
122
204
  key: 0,
@@ -129,7 +211,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
129
211
  handleOauth2Update({ authorizationUrl: v });
130
212
  })
131
213
  }, {
132
- default: withCtx(() => [..._cache[14] || (_cache[14] = [createTextVNode(" Auth URL ", -1)])]),
214
+ default: withCtx(() => [..._cache[16] || (_cache[16] = [createTextVNode(" Auth URL ", -1)])]),
133
215
  _: 1
134
216
  }, 8, ["environment", "modelValue"])) : createCommentVNode("", true), "tokenUrl" in flow.value ? (openBlock(), createBlock(RequestAuthDataTableInput_default, {
135
217
  key: 1,
@@ -141,7 +223,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
141
223
  handleOauth2Update({ tokenUrl: v });
142
224
  })
143
225
  }, {
144
- default: withCtx(() => [..._cache[15] || (_cache[15] = [createTextVNode(" Token URL ", -1)])]),
226
+ default: withCtx(() => [..._cache[17] || (_cache[17] = [createTextVNode(" Token URL ", -1)])]),
145
227
  _: 1
146
228
  }, 8, ["environment", "modelValue"])) : createCommentVNode("", true)]),
147
229
  _: 1
@@ -150,12 +232,13 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
150
232
  default: withCtx(() => [createVNode(RequestAuthDataTableInput_default, {
151
233
  environment: __props.environment,
152
234
  modelValue: flow.value["x-scalar-secret-redirect-uri"],
153
- placeholder: "https://galaxy.scalar.com/callback",
235
+ placeholder: "Optional redirect URL",
154
236
  "onUpdate:modelValue": _cache[4] || (_cache[4] = (v) => {
237
+ hasHandledRedirectPrefill.value = true;
155
238
  handleOauth2SecretsUpdate({ "x-scalar-secret-redirect-uri": v });
156
239
  })
157
240
  }, {
158
- default: withCtx(() => [..._cache[16] || (_cache[16] = [createTextVNode(" Redirect URL ", -1)])]),
241
+ default: withCtx(() => [..._cache[18] || (_cache[18] = [createTextVNode(" Redirect URL ", -1)])]),
159
242
  _: 1
160
243
  }, 8, ["environment", "modelValue"])]),
161
244
  _: 1
@@ -168,7 +251,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
168
251
  placeholder: "janedoe",
169
252
  "onUpdate:modelValue": _cache[5] || (_cache[5] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-username": v }))
170
253
  }, {
171
- default: withCtx(() => [..._cache[17] || (_cache[17] = [createTextVNode(" Username ", -1)])]),
254
+ default: withCtx(() => [..._cache[19] || (_cache[19] = [createTextVNode(" Username ", -1)])]),
172
255
  _: 1
173
256
  }, 8, ["environment", "modelValue"])]),
174
257
  _: 1
@@ -180,7 +263,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
180
263
  type: "password",
181
264
  "onUpdate:modelValue": _cache[6] || (_cache[6] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-password": v }))
182
265
  }, {
183
- default: withCtx(() => [..._cache[18] || (_cache[18] = [createTextVNode(" Password ", -1)])]),
266
+ default: withCtx(() => [..._cache[20] || (_cache[20] = [createTextVNode(" Password ", -1)])]),
184
267
  _: 1
185
268
  }, 8, ["environment", "modelValue"])]),
186
269
  _: 1
@@ -192,7 +275,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
192
275
  placeholder: "12345",
193
276
  "onUpdate:modelValue": _cache[7] || (_cache[7] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-client-id": v }))
194
277
  }, {
195
- default: withCtx(() => [..._cache[19] || (_cache[19] = [createTextVNode(" Client ID ", -1)])]),
278
+ default: withCtx(() => [..._cache[21] || (_cache[21] = [createTextVNode(" Client ID ", -1)])]),
196
279
  _: 1
197
280
  }, 8, ["environment", "modelValue"])]),
198
281
  _: 1
@@ -205,7 +288,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
205
288
  type: "password",
206
289
  "onUpdate:modelValue": _cache[8] || (_cache[8] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-client-secret": v }))
207
290
  }, {
208
- default: withCtx(() => [..._cache[20] || (_cache[20] = [createTextVNode(" Client Secret ", -1)])]),
291
+ default: withCtx(() => [..._cache[22] || (_cache[22] = [createTextVNode(" Client Secret ", -1)])]),
209
292
  _: 1
210
293
  }, 8, ["environment", "modelValue"])]),
211
294
  _: 1
@@ -218,7 +301,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
218
301
  readOnly: "",
219
302
  "onUpdate:modelValue": _cache[9] || (_cache[9] = (v) => handleOauth2Update({ "x-usePkce": v }))
220
303
  }, {
221
- default: withCtx(() => [..._cache[21] || (_cache[21] = [createTextVNode(" Use PKCE ", -1)])]),
304
+ default: withCtx(() => [..._cache[23] || (_cache[23] = [createTextVNode(" Use PKCE ", -1)])]),
222
305
  _: 1
223
306
  }, 8, [
224
307
  "enum",
@@ -236,7 +319,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
236
319
  readOnly: "",
237
320
  "onUpdate:modelValue": _cache[10] || (_cache[10] = (v) => handleSecretLocationUpdate(v))
238
321
  }, {
239
- default: withCtx(() => [..._cache[22] || (_cache[22] = [createTextVNode(" Credentials Location ", -1)])]),
322
+ default: withCtx(() => [..._cache[24] || (_cache[24] = [createTextVNode(" Credentials Location ", -1)])]),
240
323
  _: 1
241
324
  }, 8, ["environment", "modelValue"])]),
242
325
  _: 1
@@ -258,21 +341,21 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
258
341
  default: withCtx(() => [createElementVNode("div", _hoisted_2, [__props.scheme.type === "openIdConnect" ? (openBlock(), createBlock(unref(ScalarButton), {
259
342
  key: 0,
260
343
  class: "mr-1 p-0 px-2 py-0.5",
261
- loader: unref(loader),
344
+ disabled: unref(loader).isLoading,
262
345
  size: "sm",
263
346
  variant: "outlined",
264
347
  onClick: clearOauth2Secrets
265
348
  }, {
266
- default: withCtx(() => [..._cache[23] || (_cache[23] = [createTextVNode(" Clear ", -1)])]),
349
+ default: withCtx(() => [..._cache[25] || (_cache[25] = [createTextVNode(" Clear ", -1)])]),
267
350
  _: 1
268
- }, 8, ["loader"])) : createCommentVNode("", true), createVNode(unref(ScalarButton), {
351
+ }, 8, ["disabled"])) : createCommentVNode("", true), createVNode(unref(ScalarButton), {
269
352
  class: "mr-0.75 p-0 px-2 py-0.5",
270
353
  loader: unref(loader),
271
354
  size: "sm",
272
355
  variant: "outlined",
273
356
  onClick: handleAuthorize
274
357
  }, {
275
- default: withCtx(() => [..._cache[24] || (_cache[24] = [createTextVNode(" Authorize ", -1)])]),
358
+ default: withCtx(() => [..._cache[26] || (_cache[26] = [createTextVNode(" Authorize ", -1)])]),
276
359
  _: 1
277
360
  }, 8, ["loader"])])]),
278
361
  _: 1
@@ -1 +1 @@
1
- {"version":3,"file":"OAuth2.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Any config options required for the OAuth2 flow */\nexport type OAuth2Options = Pick<ApiClientConfiguration, 'oauth2RedirectUri'>\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton, useLoadingState } from '@scalar/components'\nimport type { ApiClientConfiguration } from '@scalar/types/api-reference'\nimport { pkceOptions } from '@scalar/types/entities'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { SecretsOAuthFlows } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n getEnvironmentVariables,\n type OAuthFlowAuthorizationCodeSecret,\n type OAuthFlowClientCredentialsSecret,\n type OAuthFlowPasswordSecret,\n type OAuthFlowsObjectSecret,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCredentialsLocation } from '@scalar/workspace-store/schemas/extensions/security/x-scalar-credentials-location'\nimport { type XusePkce } from '@scalar/workspace-store/schemas/extensions/security/x-use-pkce'\nimport type {\n OAuthFlow,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport OAuthScopesInput from '@/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue'\nimport { authorizeOauth2 } from '@/v2/blocks/scalar-auth-selector-block/helpers/oauth'\nimport { resolveDefaultOAuth2RedirectUri } from '@/v2/blocks/scalar-auth-selector-block/helpers/resolve-default-oauth2-redirect-url'\nimport { DataTableRow } from '@/v2/components/data-table'\n\nimport RequestAuthDataTableInput from './RequestAuthDataTableInput.vue'\n\nconst {\n environment,\n flows,\n type,\n scheme,\n selectedScopes: selectedScopesProp,\n server,\n proxyUrl,\n eventBus,\n name,\n options = {},\n} = defineProps<{\n /** Current environment configuration */\n environment: XScalarEnvironment\n /** OAuth flows */\n flows: OAuthFlowsObjectSecret\n /** Type of the OAuth flow */\n type: keyof OAuthFlowsObjectSecret\n /** Selected scopes */\n selectedScopes: string[]\n /** Security scheme */\n scheme: SecuritySchemeObjectSecret\n /** Current server configuration */\n server: ServerObject | null\n /** Proxy URL */\n proxyUrl: string\n /** Name of the security scheme */\n name: string\n /** Event bus for authentication updates */\n eventBus: WorkspaceEventBus\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst emits = defineEmits<{\n (\n e: 'update:selectedScopes',\n payload: Pick<\n ApiReferenceEvents['auth:update:selected-scopes'],\n 'scopes' | 'newScopePayload'\n >,\n ): void\n}>()\n\nconst loader = useLoadingState()\nconst { toast } = useToasts()\n\n/** The current OAuth flow based on the selected type */\nconst flow = computed(() => flows[type]!)\ntype NonImplicitFlow =\n | OAuthFlowPasswordSecret\n | OAuthFlowClientCredentialsSecret\n | OAuthFlowAuthorizationCodeSecret\n\n/** We filter selected scopes to only include scopes that are in this flow*/\nconst selectedScopes = computed(() =>\n selectedScopesProp.filter((scope) => scope in (flow.value.scopes ?? {})),\n)\n\n/** Updates the security scheme base */\nconst handleOauth2Update = (\n payload: Partial<OAuthFlow & XScalarCredentialsLocation>,\n): void => {\n // OpenIdConnect uses the secrets update for all\n if (scheme.type === 'openIdConnect') {\n return handleOauth2SecretsUpdate(payload)\n }\n\n eventBus.emit('auth:update:security-scheme', {\n payload: {\n type: scheme.type,\n flows: {\n [type]: payload,\n },\n },\n name,\n })\n}\n\n/** Updates the flow secrets */\nconst handleOauth2SecretsUpdate = (\n payload: Omit<Partial<SecretsOAuthFlows[keyof SecretsOAuthFlows]>, 'type'>,\n): void =>\n eventBus.emit('auth:update:security-scheme-secrets', {\n payload: {\n type: scheme.type,\n [type]: payload,\n },\n name,\n })\n\n/** Clears the flow secrets */\nconst clearOauth2Secrets = (): void =>\n eventBus.emit('auth:clear:security-scheme-secrets', {\n name,\n })\n\n/** Track if we have set the redirect uri */\nconst hasPrefilledRedirectUri = ref(false)\n\n/** Default the redirect-uri to the current origin if we have access to window */\nwatch(\n () =>\n (flow.value as OAuthFlowAuthorizationCodeSecret)[\n 'x-scalar-secret-redirect-uri'\n ],\n (newRedirectUri) => {\n const defaultRedirectUri = resolveDefaultOAuth2RedirectUri(options)\n\n if (\n hasPrefilledRedirectUri.value ||\n newRedirectUri ||\n !defaultRedirectUri ||\n !('x-scalar-secret-redirect-uri' in flow.value)\n ) {\n return\n }\n hasPrefilledRedirectUri.value = true\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-redirect-uri': defaultRedirectUri,\n })\n },\n { immediate: true },\n)\n\n/**\n * Authorizes the user using the specified OAuth flow.\n * Opens the appropriate OAuth dialog and/or performs the token exchange.\n */\nconst handleAuthorize = async (): Promise<void> => {\n if (loader.isLoading) {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await authorizeOauth2(\n flows,\n type,\n selectedScopes.value,\n server,\n proxyUrl,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to authorize', 'error')\n }\n}\n\n/** Updates the secret location */\nconst handleSecretLocationUpdate = (value: string): void => {\n const credentialsLocation = value === 'body' ? 'body' : 'header'\n\n if (scheme.type !== 'openIdConnect') {\n handleOauth2Update({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n}\n</script>\n\n<template>\n <!-- Access Token Display: Shows when user is already authorized -->\n <template v-if=\"Boolean(flow['x-scalar-secret-token'])\">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token']\"\n placeholder=\"QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-token': v })\n \">\n Access Token\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 items-center justify-end gap-2 border-t\">\n <ScalarButton\n class=\"mr-1 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': '',\n 'x-scalar-secret-refresh-token': '',\n })\n \">\n Clear\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n\n <!-- Authorization Form: Shows when user needs to authorize -->\n <template v-else>\n <DataTableRow>\n <RequestAuthDataTableInput\n v-if=\"'authorizationUrl' in flow\"\n containerClass=\"border-r-0\"\n :environment\n :modelValue=\"flow['x-scalar-secret-auth-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/authorize\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-auth-url': v })\n handleOauth2Update({ authorizationUrl: v })\n }\n \">\n Auth URL\n </RequestAuthDataTableInput>\n\n <RequestAuthDataTableInput\n v-if=\"'tokenUrl' in flow\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/token\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-token-url': v })\n handleOauth2Update({ tokenUrl: v })\n }\n \">\n Token URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-redirect-uri' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-redirect-uri']\"\n placeholder=\"https://galaxy.scalar.com/callback\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-redirect-uri': v })\n }\n \">\n Redirect URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <template\n v-if=\"\n 'x-scalar-secret-username' in flow && 'x-scalar-secret-password' in flow\n \">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"text-c-2\"\n :environment\n :modelValue=\"flow['x-scalar-secret-username']\"\n placeholder=\"janedoe\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-username': v })\n \">\n Username\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-password']\"\n placeholder=\"********\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-password': v })\n \">\n Password\n </RequestAuthDataTableInput>\n </DataTableRow>\n </template>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-id']\"\n placeholder=\"12345\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-client-id': v })\n \">\n Client ID\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-client-secret' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-secret']\"\n placeholder=\"XYZ123\"\n type=\"password\"\n @update:modelValue=\"\n (v) =>\n handleOauth2SecretsUpdate({ 'x-scalar-secret-client-secret': v })\n \">\n Client Secret\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-usePkce' in flow\">\n <RequestAuthDataTableInput\n :enum=\"pkceOptions\"\n :environment\n :modelValue=\"flow['x-usePkce']\"\n readOnly\n @update:modelValue=\"\n (v) =>\n handleOauth2Update({\n 'x-usePkce': v as XusePkce['x-usePkce'],\n })\n \">\n Use PKCE\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Credentials Location -->\n <DataTableRow v-if=\"type !== 'implicit'\">\n <RequestAuthDataTableInput\n :enum=\"['header', 'body']\"\n :environment\n :modelValue=\"\n (flow as NonImplicitFlow)['x-scalar-credentials-location'] || 'header'\n \"\n placeholder=\"header\"\n readOnly\n @update:modelValue=\"(v) => handleSecretLocationUpdate(v)\">\n Credentials Location\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Scopes -->\n <DataTableRow>\n <OAuthScopesInput\n :flow\n :flowType=\"type\"\n :selectedScopes\n @update:selectedScopes=\"(v) => emits('update:selectedScopes', v)\" />\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 w-full items-center justify-end border-t\">\n <!-- Allow clearing the oauth section and going back to discovery -->\n <ScalarButton\n v-if=\"scheme.type === 'openIdConnect'\"\n class=\"mr-1 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"clearOauth2Secrets\">\n Clear\n </ScalarButton>\n\n <ScalarButton\n class=\"mr-0.75 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleAuthorize\">\n Authorize\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"OAuth2.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Any config options required for the OAuth2 flow */\nexport type OAuth2Options = Pick<ApiClientConfiguration, 'oauth2RedirectUri'>\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton, useLoadingState } from '@scalar/components'\nimport type { ApiClientConfiguration } from '@scalar/types/api-reference'\nimport { pkceOptions } from '@scalar/types/entities'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { SecretsOAuthFlows } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n getEnvironmentVariables,\n type OAuthFlowAuthorizationCodeSecret,\n type OAuthFlowClientCredentialsSecret,\n type OAuthFlowPasswordSecret,\n type OAuthFlowsObjectSecret,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCredentialsLocation } from '@scalar/workspace-store/schemas/extensions/security/x-scalar-credentials-location'\nimport { type XusePkce } from '@scalar/workspace-store/schemas/extensions/security/x-use-pkce'\nimport type {\n OAuthFlow,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport OAuthScopesInput from '@/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue'\nimport {\n authorizeOauth2,\n refreshOauth2Token,\n} from '@/v2/blocks/scalar-auth-selector-block/helpers/oauth'\nimport { resolveDefaultOAuth2RedirectUri } from '@/v2/blocks/scalar-auth-selector-block/helpers/resolve-default-oauth2-redirect-url'\nimport { DataTableRow } from '@/v2/components/data-table'\n\nimport RequestAuthDataTableInput from './RequestAuthDataTableInput.vue'\n\nconst {\n environment,\n flows,\n type,\n scheme,\n selectedScopes: selectedScopesProp,\n server,\n proxyUrl,\n eventBus,\n name,\n options = {},\n} = defineProps<{\n /** Current environment configuration */\n environment: XScalarEnvironment\n /** OAuth flows */\n flows: OAuthFlowsObjectSecret\n /** Type of the OAuth flow */\n type: keyof OAuthFlowsObjectSecret\n /** Selected scopes */\n selectedScopes: string[]\n /** Security scheme */\n scheme: SecuritySchemeObjectSecret\n /** Current server configuration */\n server: ServerObject | null\n /** Proxy URL */\n proxyUrl: string\n /** Name of the security scheme */\n name: string\n /** Event bus for authentication updates */\n eventBus: WorkspaceEventBus\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst emits = defineEmits<{\n (\n e: 'update:selectedScopes',\n payload: Pick<\n ApiReferenceEvents['auth:update:selected-scopes'],\n 'scopes' | 'newScopePayload'\n >,\n ): void\n}>()\n\nconst loader = useLoadingState()\nconst { toast } = useToasts()\n\n/** The current OAuth flow based on the selected type */\nconst flow = computed(() => flows[type]!)\ntype NonImplicitFlow =\n | OAuthFlowPasswordSecret\n | OAuthFlowClientCredentialsSecret\n | OAuthFlowAuthorizationCodeSecret\n\n/** We filter selected scopes to only include scopes that are in this flow*/\nconst selectedScopes = computed(() =>\n selectedScopesProp.filter((scope) => scope in (flow.value.scopes ?? {})),\n)\n\n/** Updates the security scheme base */\nconst handleOauth2Update = (\n payload: Partial<OAuthFlow & XScalarCredentialsLocation>,\n): void => {\n // OpenIdConnect uses the secrets update for all\n if (scheme.type === 'openIdConnect') {\n return handleOauth2SecretsUpdate(payload)\n }\n\n eventBus.emit('auth:update:security-scheme', {\n payload: {\n type: scheme.type,\n flows: {\n [type]: payload,\n },\n },\n name,\n })\n}\n\n/** Updates the flow secrets */\nconst handleOauth2SecretsUpdate = (\n payload: Omit<Partial<SecretsOAuthFlows[keyof SecretsOAuthFlows]>, 'type'>,\n): void =>\n eventBus.emit('auth:update:security-scheme-secrets', {\n payload: {\n type: scheme.type,\n [type]: payload,\n },\n name,\n })\n\n/** Clears the flow secrets */\nconst clearOauth2Secrets = (): void => {\n if (loader.isLoading) {\n return\n }\n eventBus.emit('auth:clear:security-scheme-secrets', {\n name,\n })\n}\n\n/** Clears stored access and refresh tokens (authorized state) */\nconst handleClearAccessTokens = (): void => {\n if (loader.isLoading) {\n return\n }\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': '',\n 'x-scalar-secret-refresh-token': '',\n })\n}\n\n/** Track redirect URI prefill per flow instance to support document switching */\nconst prefilledFlowIdentity = ref<string | null>(null)\nconst hasHandledRedirectPrefill = ref(false)\n\nconst resolveFlowIdentity = (\n currentFlow: OAuthFlowsObjectSecret[keyof OAuthFlowsObjectSecret] | undefined,\n): string =>\n JSON.stringify({\n type,\n authorizationUrl:\n currentFlow && 'authorizationUrl' in currentFlow\n ? currentFlow.authorizationUrl\n : '',\n tokenUrl:\n currentFlow && 'tokenUrl' in currentFlow ? currentFlow.tokenUrl : '',\n refreshUrl: currentFlow?.refreshUrl ?? '',\n scopes: Object.keys(currentFlow?.scopes ?? {}),\n })\n\n/** Default the redirect-uri to the current origin if we have access to window */\nwatch(\n () => flow.value,\n (currentFlow) => {\n if (!currentFlow || !('x-scalar-secret-redirect-uri' in currentFlow)) {\n return\n }\n\n const flowIdentity = resolveFlowIdentity(currentFlow)\n if (prefilledFlowIdentity.value !== flowIdentity) {\n prefilledFlowIdentity.value = flowIdentity\n hasHandledRedirectPrefill.value = false\n }\n\n if (hasHandledRedirectPrefill.value) {\n return\n }\n\n const newRedirectUri = (currentFlow as OAuthFlowAuthorizationCodeSecret)[\n 'x-scalar-secret-redirect-uri'\n ]\n const defaultRedirectUri = resolveDefaultOAuth2RedirectUri(options)\n\n hasHandledRedirectPrefill.value = true\n\n if (newRedirectUri || !defaultRedirectUri) {\n return\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-redirect-uri': defaultRedirectUri,\n })\n },\n { immediate: true },\n)\n\n/**\n * Authorizes the user using the specified OAuth flow.\n * Opens the appropriate OAuth dialog and/or performs the token exchange.\n */\nconst handleAuthorize = async (): Promise<void> => {\n if (loader.isLoading) {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await authorizeOauth2(\n flows,\n type,\n selectedScopes.value,\n server,\n proxyUrl,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to authorize', 'error')\n }\n}\n\n/** Whether the current flow supports refreshing the access token */\nconst supportsRefreshToken = computed(() => type !== 'implicit')\n\n/**\n * Refresh URL placeholder, shows tokenUrl as hint if refreshUrl is not specified.\n * This helps users understand that tokenUrl will be used as fallback.\n */\nconst refreshUrlPlaceholder = computed(() => {\n if ('tokenUrl' in flow.value && flow.value.tokenUrl) {\n return flow.value.tokenUrl\n }\n return 'https://galaxy.scalar.com/oauth/refresh'\n})\n\n/**\n * Uses the stored refresh token to obtain a new access token\n * via grant_type=refresh_token.\n */\nconst handleRefresh = async (): Promise<void> => {\n if (loader.isLoading || type === 'implicit') {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await refreshOauth2Token(\n flows,\n type,\n proxyUrl,\n server,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to refresh token', 'error')\n }\n}\n\n/** Updates the secret location */\nconst handleSecretLocationUpdate = (value: string): void => {\n const credentialsLocation = value === 'body' ? 'body' : 'header'\n\n if (scheme.type !== 'openIdConnect') {\n handleOauth2Update({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n}\n</script>\n\n<template>\n <!-- Access Token Display: Shows when user is already authorized -->\n <template v-if=\"Boolean(flow['x-scalar-secret-token'])\">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token']\"\n placeholder=\"QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-token': v })\n \">\n Access Token\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"supportsRefreshToken\">\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow.refreshUrl ?? ''\"\n :placeholder=\"refreshUrlPlaceholder\"\n @update:modelValue=\"(v) => handleOauth2Update({ refreshUrl: v })\">\n Refresh URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 items-center justify-end gap-2 border-t\">\n <ScalarButton\n v-if=\"supportsRefreshToken\"\n class=\"p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleRefresh\">\n Refresh\n </ScalarButton>\n <ScalarButton\n class=\"mr-1 p-0 px-2 py-0.5\"\n :disabled=\"loader.isLoading\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleClearAccessTokens\">\n Clear\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n\n <!-- Authorization Form: Shows when user needs to authorize -->\n <template v-else>\n <DataTableRow>\n <RequestAuthDataTableInput\n v-if=\"'authorizationUrl' in flow\"\n containerClass=\"border-r-0\"\n :environment\n :modelValue=\"flow['x-scalar-secret-auth-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/authorize\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-auth-url': v })\n handleOauth2Update({ authorizationUrl: v })\n }\n \">\n Auth URL\n </RequestAuthDataTableInput>\n\n <RequestAuthDataTableInput\n v-if=\"'tokenUrl' in flow\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/token\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-token-url': v })\n handleOauth2Update({ tokenUrl: v })\n }\n \">\n Token URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-redirect-uri' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-redirect-uri']\"\n placeholder=\"Optional redirect URL\"\n @update:modelValue=\"\n (v) => {\n hasHandledRedirectPrefill = true\n handleOauth2SecretsUpdate({ 'x-scalar-secret-redirect-uri': v })\n }\n \">\n Redirect URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <template\n v-if=\"\n 'x-scalar-secret-username' in flow && 'x-scalar-secret-password' in flow\n \">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"text-c-2\"\n :environment\n :modelValue=\"flow['x-scalar-secret-username']\"\n placeholder=\"janedoe\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-username': v })\n \">\n Username\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-password']\"\n placeholder=\"********\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-password': v })\n \">\n Password\n </RequestAuthDataTableInput>\n </DataTableRow>\n </template>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-id']\"\n placeholder=\"12345\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-client-id': v })\n \">\n Client ID\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-client-secret' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-secret']\"\n placeholder=\"XYZ123\"\n type=\"password\"\n @update:modelValue=\"\n (v) =>\n handleOauth2SecretsUpdate({ 'x-scalar-secret-client-secret': v })\n \">\n Client Secret\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-usePkce' in flow\">\n <RequestAuthDataTableInput\n :enum=\"pkceOptions\"\n :environment\n :modelValue=\"flow['x-usePkce']\"\n readOnly\n @update:modelValue=\"\n (v) =>\n handleOauth2Update({\n 'x-usePkce': v as XusePkce['x-usePkce'],\n })\n \">\n Use PKCE\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Credentials Location -->\n <DataTableRow v-if=\"type !== 'implicit'\">\n <RequestAuthDataTableInput\n :enum=\"['header', 'body']\"\n :environment\n :modelValue=\"\n (flow as NonImplicitFlow)['x-scalar-credentials-location'] || 'header'\n \"\n placeholder=\"header\"\n readOnly\n @update:modelValue=\"(v) => handleSecretLocationUpdate(v)\">\n Credentials Location\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Scopes -->\n <DataTableRow>\n <OAuthScopesInput\n :flow\n :flowType=\"type\"\n :selectedScopes\n @update:selectedScopes=\"(v) => emits('update:selectedScopes', v)\" />\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 w-full items-center justify-end border-t\">\n <!-- Allow clearing the oauth section and going back to discovery -->\n <ScalarButton\n v-if=\"scheme.type === 'openIdConnect'\"\n class=\"mr-1 p-0 px-2 py-0.5\"\n :disabled=\"loader.isLoading\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"clearOauth2Secrets\">\n Clear\n </ScalarButton>\n\n <ScalarButton\n class=\"mr-0.75 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleAuthorize\">\n Authorize\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n</template>\n"],"mappings":"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"}
@@ -4,17 +4,17 @@ type __VLS_Props = {
4
4
  scopes: string[];
5
5
  };
6
6
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
7
+ cancel: () => any;
7
8
  submit: (scopeData: {
8
9
  name: string;
9
10
  description: string;
10
11
  }) => any;
11
- cancel: () => any;
12
12
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
13
+ onCancel?: (() => any) | undefined;
13
14
  onSubmit?: ((scopeData: {
14
15
  name: string;
15
16
  description: string;
16
17
  }) => any) | undefined;
17
- onCancel?: (() => any) | undefined;
18
18
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
19
19
  declare const _default: typeof __VLS_export;
20
20
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"OAuthScopesAddModal.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuthScopesAddModal.vue"],"names":[],"mappings":"AAuGA,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAA;AASjE,KAAK,WAAW,GAAG;IACjB,KAAK,EAAE,UAAU,CAAA;IACjB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB,CAAC;AAmLF,QAAA,MAAM,YAAY;;cA1KN,MAAM;qBACC,MAAM;;;;;cADb,MAAM;qBACC,MAAM;;;kFA4KvB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"OAuthScopesAddModal.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuthScopesAddModal.vue"],"names":[],"mappings":"AAuGA,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAA;AASjE,KAAK,WAAW,GAAG;IACjB,KAAK,EAAE,UAAU,CAAA;IACjB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB,CAAC;AAmLF,QAAA,MAAM,YAAY;;;cA1KN,MAAM;qBACC,MAAM;;;;;cADb,MAAM;qBACC,MAAM;;kFA4KvB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -1 +1 @@
1
- {"version":3,"file":"extract-security-scheme-secrets.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/helpers/extract-security-scheme-secrets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAA2C,MAAM,uCAAuC,CAAA;AAC/G,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iDAAiD,CAAA;AAClF,OAAO,KAAK,EAUV,0BAA0B,EAC3B,MAAM,yCAAyC,CAAA;AAQhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8DAA8D,CAAA;AAExG,wGAAwG;AACxG,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GAAG,WAAW,CAAC,cAAc,CAAC,CAAA;AAyKjF,6DAA6D;AAC7D,eAAO,MAAM,4BAA4B,GAEvC,QAAQ,oBAAoB,GAAG,WAAW,CAAC,cAAc,CAAC,EAC1D,WAAW,SAAS,EACpB,MAAM,MAAM,EACZ,cAAc,MAAM,KACnB,0BA2DF,CAAA"}
1
+ {"version":3,"file":"extract-security-scheme-secrets.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/helpers/extract-security-scheme-secrets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAA2C,MAAM,uCAAuC,CAAA;AAC/G,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iDAAiD,CAAA;AAClF,OAAO,KAAK,EAUV,0BAA0B,EAC3B,MAAM,yCAAyC,CAAA;AAQhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8DAA8D,CAAA;AAExG,wGAAwG;AACxG,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GAAG,WAAW,CAAC,cAAc,CAAC,CAAA;AAkLjF,6DAA6D;AAC7D,eAAO,MAAM,4BAA4B,GAEvC,QAAQ,oBAAoB,GAAG,WAAW,CAAC,cAAc,CAAC,EAC1D,WAAW,SAAS,EACpB,MAAM,MAAM,EACZ,cAAc,MAAM,KACnB,0BA2DF,CAAA"}
@@ -5,6 +5,8 @@ export type OAuth2Tokens = {
5
5
  accessToken: string;
6
6
  refreshToken?: string;
7
7
  };
8
+ /** Flow types that support token refresh (all except implicit) */
9
+ type RefreshableFlows = Exclude<keyof OAuthFlowsObjectSecret, 'implicit'>;
8
10
  /**
9
11
  * Authorize oauth2 flow
10
12
  *
@@ -17,4 +19,18 @@ activeServer: ServerObject | null,
17
19
  proxyUrl: string,
18
20
  /** Flattened environment variables used to resolve server URL templates like `{protocol}` */
19
21
  environmentVariables?: Record<string, string>) => Promise<ErrorResponse<OAuth2Tokens>>;
22
+ /**
23
+ * Exchange a refresh token for a new access token using the `grant_type=refresh_token` flow.
24
+ *
25
+ * Uses the stored refresh token, client credentials, and the token URL (or refreshUrl when available)
26
+ * to request fresh tokens from the authorization server per RFC 6749 Section 6.
27
+ */
28
+ export declare const refreshOauth2Token: (flows: OAuthFlowsObjectSecret, type: RefreshableFlows,
29
+ /** If we want to use the proxy */
30
+ proxyUrl: string,
31
+ /** We use the active server to set a base for relative URLs */
32
+ activeServer: ServerObject | null,
33
+ /** Flattened environment variables used to resolve server URL templates */
34
+ environmentVariables?: Record<string, string>) => Promise<ErrorResponse<OAuth2Tokens>>;
35
+ export {};
20
36
  //# sourceMappingURL=oauth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/helpers/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAK3E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAA;AAErF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAYhG,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AA4DD;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,sBAAsB,EAC7B,MAAM,MAAM,sBAAsB,EAClC,gBAAgB,MAAM,EAAE;AACxB,wEAAwE;AACxE,cAAc,YAAY,GAAG,IAAI;AACjC,kCAAkC;AAClC,UAAU,MAAM;AAChB,6FAA6F;AAC7F,uBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KAChD,OAAO,CAAC,aAAa,CAAC,YAAY,CAAC,CAwLrC,CAAA"}
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/helpers/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAK3E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAA;AAErF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAYhG,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,kEAAkE;AAClE,KAAK,gBAAgB,GAAG,OAAO,CAAC,MAAM,sBAAsB,EAAE,UAAU,CAAC,CAAA;AA4DzE;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,sBAAsB,EAC7B,MAAM,MAAM,sBAAsB,EAClC,gBAAgB,MAAM,EAAE;AACxB,wEAAwE;AACxE,cAAc,YAAY,GAAG,IAAI;AACjC,kCAAkC;AAClC,UAAU,MAAM;AAChB,6FAA6F;AAC7F,uBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KAChD,OAAO,CAAC,aAAa,CAAC,YAAY,CAAC,CAwLrC,CAAA;AA2HD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,sBAAsB,EAC7B,MAAM,gBAAgB;AACtB,kCAAkC;AAClC,UAAU,MAAM;AAChB,+DAA+D;AAC/D,cAAc,YAAY,GAAG,IAAI;AACjC,2EAA2E;AAC3E,uBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KAChD,OAAO,CAAC,aAAa,CAAC,YAAY,CAAC,CA+ErC,CAAA"}
@@ -181,7 +181,49 @@ var authorizeServers = async (flows, type, scopes, { code, pkce, proxyUrl } = {}
181
181
  return [/* @__PURE__ */ new Error("Failed to get an access token. Please check your credentials."), null];
182
182
  }
183
183
  };
184
+ /**
185
+ * Exchange a refresh token for a new access token using the `grant_type=refresh_token` flow.
186
+ *
187
+ * Uses the stored refresh token, client credentials, and the token URL (or refreshUrl when available)
188
+ * to request fresh tokens from the authorization server per RFC 6749 Section 6.
189
+ */
190
+ var refreshOauth2Token = async (flows, type, proxyUrl, activeServer, environmentVariables = {}) => {
191
+ const flow = flows[type];
192
+ if (!flow) return [/* @__PURE__ */ new Error("OAuth2 flow was not defined"), null];
193
+ const refreshToken = flow["x-scalar-secret-refresh-token"];
194
+ if (!refreshToken) return [/* @__PURE__ */ new Error("No refresh token available"), null];
195
+ const formData = new URLSearchParams();
196
+ formData.set("grant_type", "refresh_token");
197
+ formData.set("refresh_token", refreshToken);
198
+ const addCredentialsToBody = flow["x-scalar-credentials-location"] === "body";
199
+ const hasClientSecret = Boolean(flow["x-scalar-secret-client-secret"]);
200
+ if (addCredentialsToBody || type === "authorizationCode" && !hasClientSecret) formData.set("client_id", flow["x-scalar-secret-client-id"]);
201
+ if (addCredentialsToBody && hasClientSecret) formData.set("client_secret", flow["x-scalar-secret-client-secret"]);
202
+ if (flow["x-scalar-security-body"]) Object.entries(flow["x-scalar-security-body"]).forEach(([key, value]) => {
203
+ if (value !== void 0 && value !== null) formData.set(key, String(value));
204
+ });
205
+ try {
206
+ const headers = { "Content-Type": "application/x-www-form-urlencoded" };
207
+ if (!addCredentialsToBody && hasClientSecret) headers.Authorization = `Basic ${encode(`${flow["x-scalar-secret-client-id"]}:${flow["x-scalar-secret-client-secret"]}`)}`;
208
+ const absoluteRefreshUrl = makeUrlAbsolute(flow.refreshUrl || flow["x-scalar-secret-token-url"] || flow.tokenUrl, getActiveServerBase(activeServer, environmentVariables));
209
+ const url = shouldUseProxy(proxyUrl, absoluteRefreshUrl) ? `${proxyUrl}?${new URLSearchParams([["scalar_url", absoluteRefreshUrl]]).toString()}` : absoluteRefreshUrl;
210
+ const responseData = await (await fetch(url, {
211
+ method: "POST",
212
+ headers,
213
+ body: formData
214
+ })).json();
215
+ const accessToken = responseData[flow["x-tokenName"] || "access_token"];
216
+ const newRefreshToken = responseData.refresh_token;
217
+ if (!accessToken) return [new Error(responseData.error_description ?? responseData.error ?? "Token refresh failed"), null];
218
+ return [null, {
219
+ accessToken,
220
+ ...typeof newRefreshToken === "string" ? { refreshToken: newRefreshToken } : { refreshToken }
221
+ }];
222
+ } catch {
223
+ return [/* @__PURE__ */ new Error("Failed to refresh the access token. Please re-authorize."), null];
224
+ }
225
+ };
184
226
  //#endregion
185
- export { authorizeOauth2 };
227
+ export { authorizeOauth2, refreshOauth2Token };
186
228
 
187
229
  //# sourceMappingURL=oauth.js.map