I have created a GitHub project. In exchange for all your help, my intent is to provide an article w...
d
I have created a GitHub project. In exchange for all your help, my intent is to provide an article with a working demo for Angular/Firebase using SuperTokens so others can refer to it. However, the demo is not yet working. There are some issues with Sessions that I am unable to figure out. Here is the link: https://github.com/dleangen/supertokens-demo-1/tree/supertokens-ThirdPartyEmailPassword
To hopefully make it a bit simpler, I abandoned Firebase Auth and am using the SuperTokens UI.
r
what seems to be the session related issue?
d
Well, before that, I have a question about Session.init(). I am having issues with that. In the docs, there are two mentions of including a Session.init(): (1) https://supertokens.com/docs/thirdpartyemailpassword/quick-setup/core/saas-setup and (2) https://supertokens.com/docs/thirdpartyemailpassword/quick-setup/frontend. (1) uses the import from supertokens-node, but (2) uses the import from supertokens-auth-react. The SuperTokens interface is not the same. So I suppose that they are both needed? I find it a bit confusing to have two different interfaces with the same name, imported from different places. By the way, based on the behaviour of the code, it seems that both are required. Can you confirm? You can see where I used them here in the demo: 1. https://github.com/dleangen/supertokens-demo-1/blob/f7449c008bc9d51eeb19e53d81626908a876555e/src/main.ts#L24-L30 2. https://github.com/dleangen/supertokens-demo-1/blob/supertokens-ThirdPartyEmailPassword/src/app/components/signin/supertokens-auth.component.tsx#L7-L62
r
Yes. Both are required. One is for frontend initialisation. And one is for backend init
d
Just to confirm again: both are required on the frontend, but one is for actually initialising the frontend, while the other is for initialising the backed. Correct?
Perhaps you may want to consider renaming them? Like maybe SuperTokens.FrontEnd.init() and SuperTokens.BackEnd.init() or even SuperTokensFrontEnd, or just FrontEnd/BackEnd or whatever? Just a thought...
For a newb like me trying to understand what is going on, it is not immediately obvious...
r
> both are required on the frontend, but one is for actually initialising the frontend, while the other is for initialising the backed. Correct? Thats not true. The frontend one (supertokens-auth-react) should happen on the client side, but supertokens-node, should happen on the backend side. > Like maybe SuperTokens.FrontEnd.init() and SuperTokens.BackEnd.init() or even SuperTokensFrontEnd, or just FrontEnd/BackEnd or whatever? Just a thought... Well.. they are from two different SDKs entirely. So in a way, they are already very different.
d
Sorry, my question was very poorly formulated. I gave you the wrong links. In any case, I think I have resolved my confusion. If you like, I can tell you where I got confused in case you want to add a few words to the docs, but otherwise I am ok now. So back to my session problem...
r
> If you like, I can tell you where I got confused in case you want to add a few words to the docs Sure! Please do
d
Ok, maybe better to make a PR. I'll do that later.
r
sounds good.
thank you
d
np
When I execute the code on this page, it always comes back
false
, even after authentication. → https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/sessions/checking-session-front-end I think that the init may not be correct. Here are the FE logs:
Copy code
init: called
init: Input apiBasePath: /auth
init: Input apiDomain: http://localhost:5001
init: Input autoAddCredentials: true
init: Input cookieDomain: undefined
init: Input isInIframe: false
init: Input sessionExpiredStatusCode: 401
init: Input sessionScope: localhost
doesSessionExist: called
getIdRefreshToken: called
getIdRefreshToken: is removed
doesSessionExist: called
getIdRefreshToken: called
getIdRefreshToken: is removed
Note that no call is even being made to the BE.
r
right. So if a session deosn't exist, then doesSessionExist will return a false.
If you are creating a session via an API call, then you need to make sure that you are adding axios interceptors (in case you are using axios)
d
Ok, then clearly I have misunderstood something... Let me explain my understanding, so perhaps you can correct me.
It is my understanding that following authentication, a session is created. (Or maybe an existing session gets attached, but that is not really relevant. The important point is that once authenticated the app holds a valid session token.) It is with this session that I can (1) reload pages in my app, and (2) make calls to an API that is also connected to the session. Right now, I am just trying to reload a page, I want to secure the route. As explained on the page https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/sessions/securing-component, I need to manually check if a session exists. That is what I am doing, but the result is false, so my app keeps redirecting to the signin page.
r
Can i see the set-cookie response headers when you call the login API?
d
I have integrated the frontend UI:
I click on “Continue with Google”, and go to this screen:
This goes to Google, then Google redirects back to my site here: http://localhost:4200/signin/callback/google?state=xxxx&code=yyyy&scope=email%20https:%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%20openid&authuser=0&hd=domain.com&prompt=consent There is no call to the API. Are you saying that following this redirect, I need to call the signin API myself? I thought that the frontend component did that for me… Is my understanding incorrect?
This part: > 1) The flow starts with the frontend querying the backend SDKs API for signing in (/auth/signin POST) along with the user's credentials. Do I need to do this manually? I don't see this even happening anywhere... I thought the frontend component was supposed to take care of this for me...
r
The frontend should call this on it’s own. What’s the value of websiteBasePath in your appInfo config?
The default value of webisteBasePath is /auth. This means that the callback URI that needs to be confugured on Google’s dashboard should be /auth/callback/google. And not /signin/callback/google
d
Ah! Thank you!
I changed to "auth", and the callback is now coming to /auth/callback/google instead of /signin/callback/google as before. However, same behavior as before... 🤔 If the frontend is supposed to call the backend once the callback is received from Google, any idea why it is not doing that?
r
What’s the frontend config you have given to supertokens.init?
And are you sure that supertokens.init is being called on that callback route? The default UI on that page should be a orange loading spinner. Do you see that,
d
If you are referring to "supertokens-web-js", then yes: it is called in the app init, so for all routes: https://github.com/dleangen/supertokens-demo-1/blob/supertokens-ThirdPartyEmailPassword/src/main.ts#L35 I just tried to follow the instructions that were here: https://supertokens.com/docs/thirdpartyemailpassword/quick-setup/frontend It is from the middle of the page that shows this:
Copy code
Initialize the supertokens-web-js SDK in your angular app's root component. This will provide session management across your entire application.
The only change I made was for Angular 14 standalone components, which does not have a root component. I confirmed that the code is being called, but I don't seem to see the orange loading spinner...
r
ohhh.. you are using supertokens-web-js. Right. that will not make the API call itself. it's a non UI SDK
so you need to make the API call yourself in the callback - it has helper functions to do that
let me send you a blog that highlights this
So you can change your callback URL back to be /signin/callback/google if you like..
d
Actually, I am trying to use the prebuilt UI. I am using the UI init code ONLY within the component itself, which is how I understood the instructions here: https://supertokens.com/docs/thirdpartyemailpassword/quick-setup/frontend From the section that describes:
Copy code
In your auth component folder create a react component supertokensAuthComponent.tsx where we initialize the supertokens-auth-react SDK. This will tell SuperTokens which UI to show when the user visits the login page.
Here is the code: https://github.com/dleangen/supertokens-demo-1/blob/supertokens-ThirdPartyEmailPassword/src/app/components/signin/supertokens-auth.component.tsx#L7-L62 After that, I am trying to secure a route in the app, which is described here: https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/sessions/securing-component That page leads me here: https://supertokens.com/docs/thirdpartyemailpassword/common-customizations/sessions/checking-session-front-end That asks me to do this:
Copy code
import Session from 'supertokens-web-js/recipe/session';

async function doesSessionExist() {
      if (await Session.doesSessionExist()) {
            // user is logged in
      } else {
            // user has not logged in yet
      }
}
But that requires the Supertokens.init from "supertokens-web-js". However, you are saying that I shouldn't be using that if I am using the prebuilt code. I hope you see my circular problem...
r
Well, did you follow the angular code snippets and instructions? You need to initialise both of the SDKs for it to work.
We have an angular demo app as well with the pre built ui. Did you see that?
If you setup the routing right, then you should see the the /auth/callback/google route be handled by the pre built ui component.
/signin/callback/google *
i have cloned the repo now
and checking it out
will try and debug
since the code setup on initial inspection seems more or less fine
d
> Well, did you follow the angular code snippets and instructions? Yes, at least that was the intention. > You need to initialise both of the SDKs for it to work. Yes, I did. > We have an angular demo app as well with the pre built ui. Did you see that? I did not know. That would be very helpful. I will look again to try to find this. Thank you for mentioning it now. > If you setup the routing right, then you should see the the /auth/callback/google route be handled by the pre built ui component. > /signin/callback/google * That is my expectation. The existing app will be the most helpful way forward. Thanks.
d
Thank you!! I will check this out when I get back to my desk. Sorry that I didn't notice this before.
r
no worries! I'll iisue a PR to your repo if i find some issue
(and if i can get the repo to work)
do i need any env vars to make it work?
d
> no worries! I'll iisue a PR to your repo if i find some issue That would be awesome. It uses Angular 14 and the new standalone components. However, I don't think that should be an issue. > do i need any env vars to make it work? It uses Firebase, so it requires a Firebase project. Unless you are familiar with setting up Firebase, maybe it would be better for me to check out your demo first.
r
right ok. Please checkout the demo then. Im not too familiar with firebase setup
d
Ok, no worries!
Thanks!
r
but the demo just follows the instrs from the docs.. so not sure if there is anything new that you will find
But check it out anyway
d
I will. I believe that either I am misunderstanding the instructions, or I have made a mistake somewhere. I don't believe that the new version of Angular or the use of Firebase should have any impact.
r
I think so too
d
Just so you know, I am back at my desk today. I cloned the demo project and updated to Angular 14, then switched to using standalone components. Based on the working demo, I was easily able to find the (very stupid) problem. As predicted, it was an error on my part. My demo project is now working. I will try to propose some PRs to the docs so that hopefully others don't make the same (very stupid) mistakes that I made. I am calling these very stupid mistakes, but in fairness, there are many new things happening, so it is very easy when trying this out for the first time for these types of "stupid" problems to interfere. I wish I had realized sooner that a demo project was already available. That would have saved me a lot of time. I will now proceed with trying to integrate with Firebase, and I may try out different approaches (like using Firebase Auth for signin, but SuperTokens for session management).
r
> I wish I had realized sooner that a demo project was already available. That would have saved me a lot of time. Makes sense. I guess we can add a link to the demo app at the start of the quick setup section maybe. What were the mistakes?
d
The main mistake was in the routing configuration. I did not understand how it was supposed to work.
r
Hmm. What was the mistake in there? I didn't find anything obvious when I saw the code
d
Following authentication (at least with Google, but I assume also with other providers), the provider sends a callback to /auth/something/something. I only configured the "auth" route, but I have to actually configure the AuthComponent to intercept all children of "auth". I had assumed (wrongly) that just having a config like this would work:
Copy code
{ path: 'auth', component: AuthComponent }
But actually, it requires something more like this:
Copy code
{ path: 'auth', children: [ { path: '**', component: AuthComponent } ] }
I did not notice because I was using standalone components. I did not think it was relevant at the time. Turns out it is necessary. I only noticed when I updated the existing demo to use standalone components in Angular 14.
Like I said, a "stupid problem". 😀
r
Ahh i see. Fair enough!
d
But when several "little" things like this are all thrown together, it can take a while to figure out what is going wrong. The demo is extremely helpful.
r
d
Right, I am using Angular. Maybe it just works differently in Angular...
Oh, sorry... you are also using Angular. Let me point out the part I am referring to...
r
yes please
d
Ok, I see what you mean. Let me double check...
Yes, I just confirmed. When I change the router config from this:
Copy code
{
    path: 'auth',
    title: 'SuperTokens Demo – Sign In',
    children: [
      {
        path: '**',
        component: AuthComponent,
      },
    ],
  },
to this:
Copy code
{
    path: 'auth',
    title: 'SuperTokens Demo – Sign In',
    component: AuthComponent,
    // children: [
    //   {
    //     path: '**',
    //     component: AuthComponent,
    //   },
    // ],
  },
it stops working.
I haven't tried lazy loading standalone components yet. It seems that there is a difference perhaps between dynamic components and static components, then? I'm not really an Angular expert. I would have to do more reading.
r
I think so too.. maybe dynamic components do
**
implicitly. Also, I would recommend using dynamic components since it won't include the supertokens-auth-react + react in the bundle for non auth routes -> reducing their bundle size by quite a bit
d
Yes, makes sense. Usually I start my prototyping by just throwing everything in and optimizing later.
r
fair enough
d
In any case, now I can finally take some steps forward. Thanks for all your patient help. 👍🏻
7 Views