Hi There! I am interested in magic links. I am wo...
# support-questions-legacy
d
Hi There! I am interested in magic links. I am wondering if what I am trying to do is possible. 1. I invite a User to visit a page in my app by sending them a magic link (Note, docs for this are missing: https://supertokens.com/docs/passwordless/common-customizations/generating-magic-link-manually) 2. The URL will be of the form https://myapp.com/[magic] 3. The page is available to anybody with the magic link (in theory only the person who receives my invitation) 4. The link needs to expire after 24 hours or maybe 48 hours 5. The page/route with the magic link is visible, but NO OTHER page/route should be visible (i.e. it is not the same as authenticating to the app) 6. The regular passwordless (using email) should continue to grant general access to the app, so only the magic link is a bit different What do you think about this approach? Does my explanation make sense? Can I do this with SuperTokens, or do I need to roll my own guard for this special route? Or, is there a better way to show only one page / route in my app using a magic link only with SuperTokens? Thanks! =David
r
hey @dleangen
you can do this with supertokens.
In order to generate the magic link, you need to call the backend function (createCode: https://supertokens.com/docs/nodejs/modules/recipe_passwordless.html#createCode-1) with the email as the input.
this would return a magic link code and a preAuthSessionId using which you can make your own magic link and send it to the user.
When the user clicks on it, you can call the consume code API from the frontend with the linkCode and preAuthSessionId from the magic link to log the user in
I don't quite understand point number (5) in the above description though.
d
Hey @rp_st thanks! Regarding point #5... Let's say my app has 2 "regular" routes, and 1 "magic" route: Route a: /regular-route-a/maybe/has/sub-routes/too Route b: /regular-route-b/maybe/has/sub-routes/too These make up the “regular” pages in my app, which of course require authentication. There is also a “magic” route, which is not authenticated. It is “secured” in that only the person who knows the magic link can access it: Magic route: /[magic secret]/maybe/has/sub-routes/too So “authenticating” and “knowing the magic link” are really two different things. Does that make sense?
r
Ah right. So in that case, you should still guard those magic routes with the session guard - just like the regular routes. But in the session that is created for the magic link user, you can add something in their access token payload like "isMagicLinkUser: true" and check on the frontend that this boolean exists in the payload and only if it does, should you show the magic routes.
This can be done by overriding the createNewSession function on the backend and reading the request object (from input.userContext._default.request) to read the origin header path. If the path is the magic link one, then add this boolean to the session's access token payload before calling the original impl
d
Ok, I'll give that a try. Thanks!!
Just to be clear... Are you talking about this?
Copy code
url: '/signinup/code/consume',
So if the request is for this path, then I know it is a "magic link user"?
r
So that’s the api which the frontend calls
For consuming the link code
Does regular login also happen using magic link?
If not, then you can modify the access token payload based on if this is the path that’s being queried
d
Perhaps it would be safer to use this?
Copy code
>      body: {
>        linkCode: 'tYySg...',
>        preAuthSessionId: 'AVFnk...'
>      },
wdyt?
I assume other requests won't have that body? So I could look for the "linkCode" and "preAuthSessionId" properties?
r
Oh yea. Sure. Can do
d
It looks like I need to send along some additional data when I execute
createCode()
, but I am having trouble seeing how to do that. I tried using the
userContext
, but my data gets overwritten, so I don't see it on the server. Any ideas?
r
you could use the preAPIHook function to add custom info to the request body
and then read that on the backend
i think the createCode function should have an options param which contains the preApiHook functino
d
Ok, thanks. I am having a bit of trouble understanding preAPIHook from the docs. Is there an example somewhere I could see?
r
Which frontend SDK are you using?
d
react
r
Which recipe?
d
This is for the magic links, so I guess passwordless?
d
Oh, thanks! For some reason neither Google nor the search function on the site showed me that one. Cheers!
r
Hmmm. Weird
d
Probably just a bad search query. I was using "preAPIHook".
I configured my app to use the preAPIHook, but the hook is not getting triggered. Any ideas what I could be doing wrong? Note: in this app (subdomain), there is only supertokens-web-js and no supertokens-auth-react, but I assume that should matter, right?
r
oh i see. So for web-js, the preAPIHook is part of the function call - there is an options input which contains that
d
Right, that's what I thought, but I asked if you should show me an example, so I was trying to understand from the link you gave. 🤣
r
i can send an example shortly.
d
Awesome, thanks!! 😀
r
I think this may work:
Copy code
Passwordless.createCode({
    email: "...",
    options: {
        preAPIHook: async (context) => {
            let requestInit = context.requestInit;
            let bodyStr = requestInit.body?.toString();
            if (bodyStr !== undefined) {
                let body = JSON.parse(bodyStr);
                body = {
                    ...body,
                    "customKey": "customValue"
                }
                bodyStr = JSON.parse(body);
            } 
            context.requestInit.body = bodyStr
            return context;
        }
    }
})
d
This was VERY helpful. Thanks! Strange question, perhaps, but what is the "secret" or "magic" part of the magic link? The query part of the URL is something like:
Copy code
?rid=passwordless&preAuthSessionId=xZri2I9tmjtyibDxoEsobH3ZVKfALRMuH29gO0dvlqU=#tXCnql1-v3QoSliniHhU2kbQTbMuz0k7LKFijzGzDwQ=
I suppose the sessionID is just the session ID, but would it be the anchor part of the URL after the "#" that is the secret (so in the example above, the part starting with "tXC")?
r
yup
the part after the "#'"
d
Cool, thanks!
3 Views