Hey guys! At signup, we would like to run some ch...
# ory-selfhosting
m
Hey guys! At signup, we would like to run some checks against our own external API, before proceeding to the account creation. (these checks will depend on the data submitted in the form) It seems like we cannot use either the
before
, nor the
after
action triggers because, as per explained in the doc :
before
registration: The hook runs when a registration flow starts. (what does "starts" means here ? it means that this action trigger will happen instantly after we generate a new flow ID thanks to this endpoint https://www.ory.sh/docs/reference/api#tag/frontend/operation/createBrowserRegistrationFlow ? If so, it will happen before form data was submitted hence we won't have the necessary formData to base our checks on)
after
registration: The hook runs when a user successfully registers in the system. (So, this happens after the form has been submitted, but also after a user has successfully registered, so we won't be able to inject our own checks to potentially prevent the account creation) So, is what we are trying to do doable here ? and if so, is there a recommended way to do it ? Many thanks in advance!!
f
https://www.ory.sh/docs/guides/integrate-with-ory-cloud-through-webhooks#flow-interrupting-webhooks
When the webhook parses the response, the logic is called before the system creates a new identity.
Isn't that what you want?
a
I implemented this on one of my installations. I’ll pull the details and get back to you.
You definitely want to hook into the webhook system. I had a similar scenario where I needed to validate that users could create or login to accounts using a custom invite key. Essentially, i had an old user system and wanted to migrate users automatically to Kratos for identity and had a invite keys to allow users to sign up. This required me to send a key along with the sign up/login payload that was validated against my backend before allowing the signup/login. This would work exactly the same for you based on your description. My config:
Copy code
selfservice:
      flows:
        registration:
          after:
            webauthn:
              hooks:
              - config:
                  body: file:///etc/config/auth_upgrade.jsonnet
                  method: POST
                  response:
                    parse: false
                  url: api-url-here
                hook: web_hook
              - hook: session
          before:
            hooks:
            - config:
                body: file:///etc/config/auth_verify.jsonnet
                can_interrupt: true
                method: POST
                url: <http://api-url-here>
auth_upgrade.jsonnet:
Copy code
function(ctx) {
      legacy_id: std.get(ctx.flow.transient_payload, "legacy_id", default=""),
      invitation_id:  std.get(ctx.flow.transient_payload, "invitation_id",default=""),
      identity_id: ctx.identity.id
    }
: |
auth_verify.jsonnet:
Copy code
function(ctx) {
      legacy_id: std.get(ctx.request_headers, "X-Legacy-Id", default=[""])[0],
      invitation_id: std.get(ctx.request_headers, "X-Invitation-Id", default=[""])[0],
    }
So basically, the config is this. When a user tries registering in my UI, I pass an additional
legacy_id
JS form data field to the registration flow create request to Kratos. The before hook gets hit which calls my api listed in the
before.hooks
config section. The body of my UI form data gets passed along to the
auth_verify
jsonnet which I mutate (jsonnet functions should return an object that Kratos will forward to your API. Once it hits my API, I can do my processing and return a success or error status. So say they didn’t have a valid
invitaion_id
. I can return a 503 or 400 or whatever (non-200). Kratos will fail the registration flow creation and return an error to the UI like normal. So no sign-up will be allowed. This is a JS snippet of my
createFlow
function which triggers the browser registration flow. This occurs before the registration form is returned to the end user to be displayed to the user:
Copy code
// ...
// this is a builder pattern. you are injecting data to be sent to Kratos to generate the form
//
const injectParameters = (data, headers) => {
    headers["X-Invitation-Id"] = getSearchParam('invitation') ?? '';

  const legacyId = getLegacyId()
  if (legacyId) {
    headers["X-Legacy-Id"] = legacyId;
  }
  return JSON.stringify(data)
}

// the actual flow creation call
flow = await sdk.createBrowserRegistrationFlow(undefined, {
  transformRequest: injectParameters
})
///....
The
after
registration hook is my hook to upgrade old users which occurs once the new user form is submitted. If a user successfully logs in (so after a valid sign up), if they also logged in using an old method, I can forward that data along to a different endpoint, along with their new ID from Kratos that is generated from sign up, and send that to my API to do the migration behind the scenes. I use a React frontend, so I have to build up the form request myself. Instead of fully writing it all myself, I am using the Kratos library to inject data into the flow UI nodes. Kratos expects a node called
transient_payload
which you can pass arbitrary data. In this case I create a JSON string as the value:
Copy code
flow.ui.nodes.push({
      "type": "input",
      "group": "default",
      "attributes": {
        "name": "transient_payload",
        "type": "hidden",
        value: JSON.stringify(transientData),
        "required": false,
        "disabled": false,
        "node_type": "input"
      },
      "messages": [],
      "meta": {
        "label": {
          "id": 88090001,
          "text": "Legacy Id",
          "type": "info"
        }
      }
    })
Be aware, the after hook changes depending on what you do with the response. Per the doc above: > When using an
after
registration hook, you can define the specific point in the flow where this webhook is called: > • When the webhook parses the response, the logic is called before the system creates a new identity. > • When the webhook does not parse the response, the logic is called after the system creates a new identity. > I’d be more than happy to jump on a call if you need more clarification on this. It’s really tricky to get the first time around. Like Dominik said, that link will have the webhook and jsonnet stuff, but I found this diagram helpful: https://www.ory.sh/docs/kratos/self-service/flows/user-registration
m
Gosh, guys. You are simply amazing. Thank you so so much, for the answers. Helping random people on the internet, for the win! 💯 I will def try your solution @astonishing-morning-18498!! Will keep you guys updated
f
Props to @astonishing-morning-18498. Really nice outline
a
No problem. I really like Ory's software so I'm always down to help people get it up and running.
m
I think we are going to be good! Thanks to
response: parse: true
I juste made my flow be interrupted if our own API throws an error. Thanks again so much for these pure acts of kindness. Truly and genuinely appreciated that. Have both of yourselves an excellent rest of week ! 🤘
(and we already had some jsonnet that was extracting some values from the URL params, but I will also keep the transient payload possibility in mind !)