mysterious-rose-40371
10/22/2024, 4:43 PMbefore
, 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!!faint-helmet-53309
10/23/2024, 10:55 PMWhen the webhook parses the response, the logic is called before the system creates a new identity.
Isn't that what you want?
astonishing-morning-18498
10/23/2024, 11:07 PMastonishing-morning-18498
10/24/2024, 1:34 AMselfservice:
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>
astonishing-morning-18498
10/24/2024, 1:37 AMfunction(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:
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],
}
astonishing-morning-18498
10/24/2024, 1:48 AMlegacy_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:
// ...
// 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:
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-registrationmysterious-rose-40371
10/24/2024, 12:05 PMfaint-helmet-53309
10/24/2024, 12:18 PMastonishing-morning-18498
10/24/2024, 2:00 PMmysterious-rose-40371
10/24/2024, 11:12 PMresponse: 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 ! 🤘mysterious-rose-40371
10/25/2024, 12:07 PM