search

Home  >  Q&A  >  body text

Ory Kratos setup process where password cannot be changed successfully

<p>I created my own user interface for the Ory Kratos setup process. The problem I'm having is that although the message comes back that my settings have been updated successfully, my new password isn't reflected and I haven't successfully recovered my account. Below is the code snippet I use to render the UI using Vue 3. </p> <pre class="brush:js;toolbar:false;">// SettingsVue.vue <template> <div id="settings"> <HomeTopbar :views="[]" /> <div class="settings-wrapper"> <h1 class="poppins fs_3 fw_6">Recover your password</h1> <OryFlow v-if="settingsFlow" :flow="settingsFlow" title="Login" form-id="settings-form" /> </div> </div> </template> <script setup lang="ts"> import { ref } from 'vue'; /* ory */ import { injectStrict } from '@/utils'; import { $ory } from '@/plugins/ory'; import { makeHandleGetFlowError } from '@/utils/flows'; /* types */ import type { SelfServiceSettingsFlow } from '@ory/kratos-client'; /* composables */ import { useRoute, useRouter } from 'vue-router'; /* components */ import OryFlow from '@/components/flows/OryFlow.vue'; import HomeTopbar from '@/components/ui/HomeTopbar.vue'; const ory = injectStrict($ory); const route = useRoute(); const router = useRouter(); const settingsFlow = ref<SelfServiceSettingsFlow | undefined>(); const handleGetFlowError = makeHandleGetFlowError(router); // check if we have a flow param const { flow } = route.query; const initializeSelfServiceSettingsFlowForBrowsers = () => ory .initializeSelfServiceSettingsFlowForBrowsers() .then((response) => { settingsFlow.value = response.data; router.replace({ query: { flow: response.data.id, }, }); }) .catch(handleGetFlowError); if (typeof flow !== 'string') { // if there's no flow in our route, // we need to initialize our login flow initializeSelfServiceSettingsFlowForBrowsers(); } else { ory .getSelfServiceSettingsFlow(flow) .then((response) => { settingsFlow.value = response.data; }) .catch(handleGetFlowError); } </script> <style scoped lang="scss"> #settings { width: 100%; height: 100%; .settings-wrapper { margin: var(--space-5) auto 0 auto; padding: 0 var(--space-3); margin-top: var(--space-4); width: 300px; } } </style> </pre> <pre class="brush:js;toolbar:false;">#OryFlow.vue <template> <div class="ory-flow"> <form :id="formId" :action="flow.ui.action" :method="flow.ui.method"> <OryUiNode v-for="node in flow.ui.nodes" :key="getNodeId(node)" :id="getNodeId(node)" :node="node" class="ui-node" /> </form> <div class="messages" v-if="flow.ui.messages"> <OryUiMessage v-for="message in flow.ui.messages" :message="message" /> </div> </div> </template> <script setup lang="ts"> import type { SelfServiceLoginFlow, SelfServiceRegistrationFlow, SelfServiceRecoveryFlow, SelfServiceSettingsFlow, SelfServiceVerificationFlow, } from '@ory/kratos-client'; import OryUiNode from './OryUiNode.vue'; import OryUiMessage from './OryUiMessage.vue'; import { getNodeId } from '@ory/integrations/ui'; defineProps<{ flow: | SelfServiceLoginFlow | SelfServiceRegistrationFlow | SelfServiceRecoveryFlow | SelfServiceSettingsFlow | SelfServiceVerificationFlow; formId?: string; }>(); </script> <style scoped lang="scss"> .ui-node .ui-node { margin-top: var(--space-2); } .message { margin-top: var(--space-2); } </style> </pre>
P粉776412597P粉776412597480 days ago619

reply all(1)I'll reply

  • P粉029327711

    P粉0293277112023-09-01 17:13:19

    So solving this problem is actually pretty straightforward and obvious, which became apparent after I reviewed the source code for the React Self-Service UI created and maintained by the Ory team.

    If you submit all UI node groups together into the same form, it will only execute on the default group and one other group. In my case, after successfully processing the profile group, it ignored the password group. The solution I followed is basically the same as the one provided in the repository I mentioned in the previous paragraph. Implement a filtering mechanism that allows you to use two separate forms to separate the values ​​when the form is submitted. Remember that you must always submit the default group as it includes your CSRF token .

    Here is the updated code that solved my problem:

    First, add support for the :only attribute for filtering nodes:

    // OryFlow.vue现在支持通过'only'属性进行过滤
    <template>
      <div class="ory-flow">
        <form :id="formId"
          :action="flow.ui.action"
          :method="flow.ui.method"
        >
          <OryUiNode v-for="node in nodes"
            :id="getNodeId(node)"
            :key="getNodeId(node)"
            :node="node"
            class="ui-node"
          />
        </form>
        <div v-if="flow.ui.messages"
          class="messages"
        >
          <OryUiMessage v-for="message in flow.ui.messages"
            :key="message.id"
            :message="message"
          />
        </div>
      </div>
    </template>
    
    <script setup lang="ts">
    import type {
      SelfServiceLoginFlow,
      SelfServiceRegistrationFlow,
      SelfServiceRecoveryFlow,
      SelfServiceSettingsFlow,
      SelfServiceVerificationFlow,
    } from '@ory/kratos-client';
    import OryUiNode from './OryUiNode.vue';
    import OryUiMessage from './OryUiMessage.vue';
    import { getNodeId } from '@ory/integrations/ui';
    import { computed, toRefs } from 'vue';
    
    const props = defineProps<{
      flow:
        | SelfServiceLoginFlow
        | SelfServiceRegistrationFlow
        | SelfServiceRecoveryFlow
        | SelfServiceSettingsFlow
        | SelfServiceVerificationFlow;
      formId?: string;
      only?: string | string[];
    }>();
    
    const { flow, only } = toRefs(props);
    
    const nodes = computed(() => {
      if (!only?.value) {
        return flow.value.ui.nodes;
      }
    
      const onlyArr: string[] = Array.isArray(only.value) ? only.value : [only.value];
      const onlyMap = onlyArr.reduce((acc, curr: string) => {
        acc[curr] = true;
        return acc;
      }, {} as Record<string, boolean>);
    
      return flow.value.ui.nodes.filter((node) => onlyMap[node.group]);
    });
    </script>
    

    Next, use this new attribute in a form to filter only the node groups password and default. You can use the same method to filter profile and default in another form.

    // SettingsView.vue
    <template>
      <div id="settings">
        <HomeTopbar :views="[]" />
    
        <div class="settings-wrapper">
          <h1 class="poppins fs_3 fw_6">Recover your password</h1>
          <!-- 在这里添加only属性 -->
          <OryFlow v-if="settingsFlow"
            :flow="settingsFlow"
            title="Login"
            form-id="settings-form"
            :only="[ 'password', 'default' ]"
          />
        </div>
      </div>
    </template>
    

    reply
    0
  • Cancelreply