https://supertokens.com/ logo
Title
a

Alen

12/08/2022, 5:51 AM
Hi, I just wanted to know about how we can integrate supertokens with SAML. For eg. We are providing Google provider for third party auth. So if we want to provide our app as a custom application in Google workspace SSO. How will I be able to configure it with supertokens third party auth. Even if I get a minimum information from your side , it would be really helpful.
s

sattvikc

12/08/2022, 5:52 AM
hey @Alen, we do support SAML
let me share the link to the documentation
let us know if you have any specific questions
r

rp

12/08/2022, 5:56 AM
Also, google workspaces can work with OAuth 2.0. No need to use SAML?
a

Alen

12/08/2022, 5:58 AM
Thanks, I will look into it.
Hi, Just out of curiosity, I'm new to this space. So in my knowledge Supertokens acts as an identity provider right ? Correct me if I'm wrong. So does supertokens support SSO ?
r

rp

12/08/2022, 9:52 AM
We are an ID provider, but we are not an OAuth or SAML provider yet.
But we are OAuth and SAML clients
a

Alen

12/08/2022, 9:55 AM
So if we want to introduce SAML or OAuth to our application, we have to separately configure it right with other Oauth or SAML providers ?
Supertokens will have no link in this right ?
Or do we have to add custom providers details to supertoken's recipe and configure it ?
In your doc its written "SuperTokens is not a SAML client.", that why I got confused.
s

sattvikc

12/08/2022, 10:08 AM
Supertokens is not a SAML client directly, what we support is as an OAuth2 client. WIth the help of a service like BoxyHQ, which acts as an adapter, exposes OAuth2 using a SAML. our documentation explains all the necessary setup instructions for that.
a

Alen

12/08/2022, 10:09 AM
Ok got it.
Do I have to set anything specific for google workspace to work ?
s

sattvikc

12/08/2022, 10:20 AM
we have GoogleWorkspaces as an in built thirdparty provider, you could use that instead of the Google provider
a

Alen

12/08/2022, 10:22 AM
Ok got it, any reference for that ? Or could I know the list of default in built providers list ?
s

sattvikc

12/08/2022, 10:27 AM
So on the backend you would import GoogleWorkspaces instead of Google (from our examples) and use that. On the frontend, follow this guide (https://supertokens.com/docs/thirdparty/common-customizations/sign-in-and-up/custom-providers) to add a custom button component and use the id as "google-workspaces"
a

Alen

12/08/2022, 10:31 AM
Thanks a lot.
Also just wanted to know, we have different organization clients, so how can I restrict that only that workspace domain users can login ?
s

sattvikc

12/08/2022, 10:36 AM
along with clientId and clientSecret, GoogleWorkspaces accepts
hd
which can be used to restrict the domain. something like:
ts
GoogleWorkspaces({
  clientId: '...',
  clientSecret: '...',
  hd: 'supertokens.com'
})
a

Alen

12/08/2022, 10:37 AM
Thanks and can multiple hd parameters can be provided ?
s

sattvikc

12/08/2022, 10:39 AM
no, google accepts either a '*' which allows all domains or a specific domain
a

Alen

12/08/2022, 10:40 AM
Ok got it.
s

sattvikc

12/08/2022, 10:41 AM
What you can still do is, use '*' for the hd and then override the SignInUp function and validate the email id before allowing the user to login.
a

Alen

12/08/2022, 10:43 AM
Ok thanks, seems helpful. Will try that.
ThirdPartyPasswordless.GoogleWorkspaces({
                    clientId: config.socialAuthConfig.google.googleClientId,
                    clientSecret: config.socialAuthConfig.google.googleClientSecret,
                    hd: 'supertokens.com'
                }),
I tried this, it listed me with only workspaces emails, but its not throwing any error with other workspace email addresses.
Like how will this hd work ? Will it only show supertokens.com domain workspace email addresses or others too and the on sign up/ in if we use other email it will throw error ?
s

sattvikc

12/08/2022, 10:50 AM
Firstly, this parameter is handled by google, where it will show / allow only users from that domain. Upon callback, we also verify if the hd matches with the user's email.
a

Alen

12/08/2022, 10:51 AM
So I kept the same hd and I used the my domain email address. ie. blocksurvey.org and it created an account for me.
s

sattvikc

12/08/2022, 10:51 AM
Let me check on that and update you
a

Alen

12/08/2022, 10:52 AM
I'm using the same google secret key and client id for workspace also. IS that the reason ?
s

sattvikc

12/08/2022, 10:52 AM
I don't think that's the reason, let me get back to you
a

Alen

12/08/2022, 10:53 AM
Sure
s

sattvikc

12/08/2022, 10:55 AM
the google suggests that one should not rely on the hd parameter, as it's used only for UI optimization. Which means, you'll have to override the SignInUp function and validate the email. Seems like the google is returning the same hd that we pass in.
a

Alen

12/08/2022, 10:56 AM
Ok got it.
When I click the google workspace, its redirecting to google auth page right, there in the payload
hd:  *
, but I have set
hd: 'supertokens.com'
s

sattvikc

12/08/2022, 11:00 AM
could u share your frontend supertokens init code ?
a

Alen

12/08/2022, 11:00 AM
Sure
SuperTokens.init({
        appInfo: {
          apiDomain: Constants.SUPERTOKENS_SVC_URL,
          apiBasePath: "/auth",
          appName: "blocksurvey",
        },
        recipeList: [
          Session.init(),
          ThirdPartyPasswordless.init()
        ],
      });
s

sattvikc

12/08/2022, 11:01 AM
are u using the web-js or the auth-react SDK?
a

Alen

12/08/2022, 11:01 AM
web js
s

sattvikc

12/08/2022, 11:02 AM
could you share your code snippet for the login action ?
a

Alen

12/08/2022, 11:03 AM
async handleThirdPartyAuthCallback() {
    try {
      const response = await thirdPartySignInAndUp();
      if (response.status === "OK") {
        if (response.createdNewUser) {
          // sign up successful
          this.supertokensId = response.user.id;
          this.getYourSecretKey();
          this.errorMsg = "";

          // Add user details to firebase collection
          this.emailService.addUserToSupertokensCollectionInFirebase(response.user);
        } 
      } else {
        window.alert("No email provided by social sign up. Please use another form of sign up.");
        this.emailService.redirectToPage(this.redirectTo, 'signup', this.methods);
      }
    } catch (err: any) {
      if (err.isSuperTokensGeneralError === true) {
        // this may be a custom error message sent from the API by you.
        window.alert(err.message);
      } else {
        window.alert("Oops! Something went wrong.");
      }
      this.emailService.redirectToPage(this.redirectTo, 'signin', this.methods);
    }
  }
s

sattvikc

12/08/2022, 11:04 AM
not this one. the one u use to redirect
a

Alen

12/08/2022, 11:04 AM
async thirdPartySignUpClicked(provider) {
    try {
      const authUrl = await getThirdPartyAuthorisationURLWithQueryParamsAndSetState({
        providerId: provider,
        authorisationURL: Constants.DOMAIN_URL + "/signup",
      });

      // we redirect the user for auth.
      window.location.assign(authUrl);

    } catch (err: any) {
      if (err.isSuperTokensGeneralError === true) {
        // this may be a custom error message sent from the API by you.
        window.alert(err.message);
      } else {
        window.alert("Oops! Something went wrong.");
      }
      // redirect on failure
      this.emailService.redirectToPage(this.redirectTo, 'signup', this.methods);
    }
  }
s

sattvikc

12/08/2022, 11:08 AM
sorry there was a mistake in my suggestion, plz use this in the backend:
ts
GoogleWorkspaces({
  clientId: '...',
  clientSecret: '...',
  domain: 'supertokens.com'
})
a

Alen

12/08/2022, 11:13 AM
Thanks I guess its working.
How can I catch this particular error ? and send custom error message ? Error: Please use a Google Workspace ID to login
r

rp

12/08/2022, 11:20 AM
Override the thirdPartySignInUpPOST api, call the original impl, catch the error from there, and send back a general_error status with a message to the frontend.
a

Alen

12/08/2022, 11:21 AM
Got it. thanks.
Hi , I was going through this SAML demo with BoxyHQ. https://github.com/supertokens/jackson-supertokens-express For running this what all prerequisite is needed ?
s

sattvikc

12/12/2022, 6:39 AM
Please refer our SAML guide here - https://supertokens.com/docs/thirdparty/common-customizations/saml/what-is-saml Other sections in the documentation specifies all the steps involved.
the readme of the specified repository also has the necessary steps to run the demo. let me know if you are facing any difficulty in any of the steps
a

Alen

12/12/2022, 6:41 AM
No I wanted to know, whether I require docker in my system or postgres server running ?
Also is there any way with BoxyHq apart from self hosted. Will I get there own hosted services ?
s

sattvikc

12/12/2022, 6:44 AM
for development purposes, docker is a preferred way to setup since, boxy and postgres can be run with minimal steps.
r

rp

12/12/2022, 6:44 AM
hey @Alen we do host boxyhq containers as well
but it's a paid option and would be happy to discuss the pricing over a call.
a

Alen

12/12/2022, 6:45 AM
Ok got it. Let me discuss with my team and comeback to you.
r

rp

12/12/2022, 6:45 AM
sounds good.
a

Alen

12/12/2022, 7:08 AM
So just wanted to know, if you host boxyhq containers for us, should we do any separate configurations with boxyhq ?
So let me clear out our requirement. BlockSurvey should be available as a cloud application to any of the SSO providers. Our enterprise customers if they want to give access to BlockSurvey for their employees, they can login using their provider and access BlockSurvey. So for eg. If our client uses Microsoft as their SSO provider, when the employees sign in using Microsoft account , it should list BlockSurvey application and on click of that if they logged in successfully, it should take them to our dashboard page. This authentication should happen using SAML.
So what should I do for this, and how I can configure it using Both Supertokens and BoxyHQ.
We would be happy if we go with BoxyHQ itself as you have support with them. I'm new to this SAML area, that why just wanted to clear things off.
r

rp

12/12/2022, 7:15 AM
Right. So for that, we will host boxyhq for you and you can call the APIs we expose to create a tenant and integrate with SuperTokens
i can run you through the flow over a call. I know the docs are not very explanatory for SAML at the moment.
a

Alen

12/12/2022, 7:16 AM
yeah that would be good. So when will be a good time to have a call ?
r

rp

12/12/2022, 7:17 AM
can do tomorrow afternoon
2 pm IST
a

Alen

12/12/2022, 7:17 AM
Sure, sounds good.
r

rp

12/12/2022, 7:17 AM
DM me your emial please. I'll send an invite
a

Alen

12/12/2022, 7:17 AM
alen@blocksurvey.org
r

rp

12/12/2022, 7:18 AM
invite sent!
a

Alen

12/12/2022, 7:19 AM
thanks a lot.
r

rp

12/12/2022, 8:15 AM
hey @Alen i have changed the time of the call to 3:30 pm. Hope that works.
a

Alen

12/12/2022, 8:16 AM
Yeah it works.
r

rp

12/12/2022, 8:18 AM
cool
a

Alen

12/16/2022, 7:31 AM
Hey, I wanted to know the difference between thirdPartyId and supertokensTenantId in SAMl multi tenant config
r

rp

12/16/2022, 7:31 AM
hey!
so third party ID will be the same for all tenants. You can keep it as "saml" for example.
and supertokensTenantId is unique ID per tenant. The value of this can be the same as what you gave to boxyhq
a

Alen

12/16/2022, 7:33 AM
is it same id which you gave saml-jackson for frontend backend ?
Or can it be separate
r

rp

12/16/2022, 7:33 AM
> is it same id which you gave saml-jackson for frontend backend ? Yea same. So if the
id
in frontend and backend is called
saml-jackson
, this should also be called that.
(im talking about thirdPartyId)
a

Alen

12/16/2022, 7:34 AM
Yeah understood. thanks.
From frontend how will I pass the client id and secret key using userContext ?
Which APi I have to override for that in frontend
r

rp

12/16/2022, 7:35 AM
u don't need to pass it from the frontend.
you only need to pass the tenantid from the frontend
a

Alen

12/16/2022, 7:37 AM
Ok so no need of usercontext then right. Directly if I send the tenant id I can fetch the client details using this get API
"/recipe/thirdparty/tenant/config"
. Am I correct?
r

rp

12/16/2022, 7:39 AM
yes correct
and you can override the getAuthorisationURLGET API and signInUpPOST API to get the tenantId, query the core to get the clientId and secret, and then add those to the user context
Then you can read the userContext in the custom provider
a

Alen

12/16/2022, 7:41 AM
how can I add it to userContext?
r

rp

12/16/2022, 7:43 AM
just something like input.userContext.client_id = ...
a

Alen

12/16/2022, 7:48 AM
Ok sorry, Got little confused, In frontend which function I have to send tenant id ? Is it
getThirdPartyAuthorisationURLWithQueryParamsAndSetState()
. do I have to override this function and then send tenant id using usercontext ?
Do I have to send something like this ?
const authUrl = await getThirdPartyAuthorisationURLWithQueryParamsAndSetState({
        providerId: provider,
        providerClientId : 'tenantId',

        authorisationURL: Constants.DOMAIN_URL + "/signup",
      });
r

rp

12/16/2022, 8:10 AM
> Ok sorry, Got little confused, In frontend which function I have to send tenant id ? Is it getThirdPartyAuthorisationURLWithQueryParamsAndSetState(). do I have to override this function and then send tenant id using usercontext ? Yes in this and in the signinup function. In both the cases, you use the preAPIHook to add the tenantId to the request body.
the providerClientId shouldn't be the tenantId.
on the frontend, see how the preAPiHook is defined here to add the tenantId to the requests being made: https://github.com/supertokens/jackson-supertokens-express/blob/main/app/src/App.js#L52
and we override the API on the backend to read the request in these two APIs: https://github.com/supertokens/jackson-supertokens-express/blob/main/api/app.js#L43
a

Alen

12/16/2022, 8:27 AM
const authUrl = await getThirdPartyAuthorisationURLWithQueryParamsAndSetState({
        providerId: provider,
        options: {
          preAPIHook: async (context: any) => {
            let url = new URL(context.url);
            let action = context.action;

            if (action === 'GET_AUTHORISATION_URL') {
              let tenantId = 'test'
              localStorage.setItem("saml-tenant-id", tenantId)
              url.searchParams.append('tenant', tenantId);
              url.searchParams.append('product', 'saml-jackson');
            }

            if (action === 'THIRD_PARTY_SIGN_IN_UP') {
              let tenantId = localStorage.getItem("saml-tenant-id");
              url.searchParams.append('tenant', tenantId);
              url.searchParams.append('product', 'saml-jackson');
            }

            return {
              requestInit: context.requestInit,
              url: url.href,
            };
          },
        },
        authorisationURL: Constants.DOMAIN_URL + "/signup",
      });
Is this right way for sending tenant id ? My recipe is thirdpartypasswordless. Is this the action 'THIRD_PARTY_SIGN_IN_UP' used for my recipe.
r

rp

12/16/2022, 8:32 AM
So the pre APi hook here will only have the request for
GET_AUTHORISATION_URL
since you are just calling that function
and wherever you call signinup function, there too add a pre APi hook
a

Alen

12/16/2022, 8:40 AM
Ok,
let action = context.action;
this is undefined.
action is not present in the context
r

rp

12/16/2022, 8:40 AM
yea. So you don't need action here cause there is just one API call being made
the example app link i sent above is adding the pre api hook on the supertokens init level
here you are adding it on the function level
therefore no context required
a

Alen

12/16/2022, 8:42 AM
Got it, thanks for your support.
`authorisationUrlGET: async (input) => { input.userContext.request = input.options.req.original; let request = input.userContext.request; let tenant = request === undefined ? "" : request.query.tenant; let product = request === undefined ? "" : request.query.product; const profile = await axios({ method: 'get', url:
https://2b2279d150ffbe9aaad08e5-us-east-1.aws.supertokens.io:3567/recipe/thirdparty/tenant/config?thirdPartyId=${product}&supertokensTenantId=${tenant}
, headers: { 'api-key': 'secret', }, }); let client_id = profile.data.config.client_id; let client_secret = profile.data.config.client_secret; input.userContext.client_id = client_id; input.userContext.client_secret = client_secret; return originalImplementation.authorisationUrlGET(input); },`
I'm trying to fetch the tenant's client id and secret and I'm able to fetch it but somehow its throwing some other error like
TypeError: Cannot read properties of undefined (reading 'params')
    at Object.<anonymous> (C:\BlockSurvey Projects\blocksurvey-supertoken-function\node_modules\supertokens-node\lib\build\recipe\thirdparty\api\implementation.js:45:75)
    at Generator.next (<anonymous>)
    at C:\BlockSurvey Projects\blocksurvey-supertoken-function\node_modules\supertokens-node\lib\build\recipe\thirdparty\api\implementation.js:30:75
    at new Promise (<anonymous>)
    at __awaiter (C:\BlockSurvey Projects\blocksurvey-supertoken-function\node_modules\supertokens-node\lib\build\recipe\thirdparty\api\implementation.js:12:16)
    at Object.authorisationUrlGET (C:\BlockSurvey Projects\blocksurvey-supertoken-function\node_modules\supertokens-node\lib\build\recipe\thirdparty\api\implementation.js:42:20)
    at Object.proxy._call (C:\BlockSurvey Projects\blocksurvey-supertoken-function\node_modules\supertokens-js-override\lib\build\index.js:56:56)
    at Object.ret.<computed> [as authorisationUrlGET] (C:\BlockSurvey Projects\blocksurvey-supertoken-function\node_modules\supertokens-js-override\lib\build\getProxyObject.js:27:29)
    at Object.authorisationUrlGET (C:\BlockSurvey Projects\blocksurvey-supertoken-function\index.js:408:59)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
index.js:408:59
this line points to
return originalImplementation.authorisationUrlGET(input);
Am I doing something wrong ?
r

rp

12/16/2022, 9:35 AM
this does seem fine on first look
the error might be coming from the custom provider implementation - what is happening in there?
a

Alen

12/16/2022, 9:36 AM
in frontend ?
`{ id: "saml-jackson", get: async (redirectURI, authCodeFromRequest, userContext) => { console.log(userContext); let client_id = userContext.client_id; let client_secret = userContext.client_secret; return { accessTokenAPI: { url:
https://7193f3e14ea770f517937-us-east-1.aws.supertokens.io:5125/api/oauth/token
, params: { client_id, client_secret, grant_type: "authorization_code", redirect_uri: redirectURI || "", code: authCodeFromRequest || "", } }, ...`
This is the custom provider code
r

rp

12/16/2022, 9:38 AM
does the execution come in the
get
function? Oh and also, the get function is not async. So you should remove the
async
keyword
a

Alen

12/16/2022, 10:12 AM
Thanks the issue is solved, async was the issue.
r

rp

12/16/2022, 10:12 AM
ah nice
a

Alen

12/16/2022, 10:15 AM
But dont know after successful auth when signinup method is called it throws this error
TypeError: Cannot read properties of undefined (reading 'startsWith')
    at isUsingDevelopmentClientId (C:\BlockSurvey Projects\blocksurvey-supertoken-function\node_modules\supertokens-node\lib\build\recipe\thirdparty\api\implementation.js:199:22)
    at Object.<anonymous> (C:\BlockSurvey Projects\blocksurvey-supertoken-function\node_modules\supertokens-node\lib\build\recipe\thirdparty\api\implementation.js:90:25)
    at Generator.next (<anonymous>)
    at C:\BlockSurvey Projects\blocksurvey-supertoken-function\node_modules\supertokens-node\lib\build\recipe\thirdparty\api\implementation.js:30:75
    at new Promise (<anonymous>)
    at __awaiter (C:\BlockSurvey Projects\blocksurvey-supertoken-function\node_modules\supertokens-node\lib\build\recipe\thirdparty\api\implementation.js:12:16)
    at Object.signInUpPOST (C:\BlockSurvey Projects\blocksurvey-supertoken-function\node_modules\supertokens-node\lib\build\recipe\thirdparty\api\implementation.js:85:20)
    at Object.proxy._call (C:\BlockSurvey Projects\blocksurvey-supertoken-function\node_modules\supertokens-js-override\lib\build\index.js:56:56)
    at Object.ret.<computed> [as thirdPartySignInUpPOST] (C:\BlockSurvey Projects\blocksurvey-supertoken-function\node_modules\supertokens-js-override\lib\build\getProxyObject.js:27:29)
    at Object.thirdPartySignInUpPOST (C:\BlockSurvey Projects\blocksurvey-supertoken-function\index.js:441:73)
My thirdPartySignInUpPOST override func looks like this.
thirdPartySignInUpPOST: async function (input) {
                            try {
                                if (originalImplementation.thirdPartySignInUpPOST) {
                                    input.userContext.request = input.options.req.original
                                    return await originalImplementation.thirdPartySignInUpPOST(input);
                                }
                            } catch (err) {
                                if (err.message === "Cannot sign up as email already exists") {
                                    // this error was thrown from our function override above.
                                    // so we send a useful message to the user
                                    return {
                                        status: "GENERAL_ERROR",
                                        message: "Seems like you already have an account with another method. Please use that instead."
                                    }
                                }
and this is my frontend call for the same
const response = await thirdPartySignInAndUp({
        options: {
          preAPIHook: async (context: any) => {
            let url = new URL(context.url);
            let tenantId = 'alen'
            localStorage.setItem("saml-tenant-id", tenantId)
            url.searchParams.append('tenant', tenantId);
            url.searchParams.append('product', 'saml-jackson');

            return {
              requestInit: context.requestInit,
              url: url.href,
            };
          },
        }
r

rp

12/16/2022, 10:22 AM
where do you call startsWith function?
a

Alen

12/16/2022, 10:22 AM
no where,
index.js:441:73
points at
return await originalImplementation.thirdPartySignInUpPOST(input);
r

rp

12/16/2022, 10:23 AM
hmm. Can you wait for @sattvikc to help out over here?
he should be free sometime tomorrow
a

Alen

12/16/2022, 10:24 AM
Sure. got just had one doubt. why do we have to pass the tenant details in signinuppost call ?
Only for authorisationUrlGET its required right ?
to fetch the client id and secret
r

rp

12/16/2022, 10:26 AM
cause you need client id and secret in that API also
a

Alen

12/16/2022, 10:26 AM
Ok, so in which call should I pass those values, I think I wasn't passing client details for that call.
That maybe the issue
r

rp

12/16/2022, 10:27 AM
what do you mean which call?
on the frontend or backend?
a

Alen

12/16/2022, 10:27 AM
backend
r

rp

12/16/2022, 10:27 AM
no i mean you are supposed to override
thirdPartySignInUpPOST
which you have done
and add to the userContext client_id and client_secret
before calling originalimpl
a

Alen

12/16/2022, 10:28 AM
but in this I'm not passing client id and secret again right
thirdPartySignInUpPOST: async function (input) {
                            try {
                                if (originalImplementation.thirdPartySignInUpPOST) {
                                    input.userContext.request = input.options.req.original
                                    return await originalImplementation.thirdPartySignInUpPOST(input);
                                }
                            } catch (err) {
                                if (err.message === "Cannot sign up as email already exists") {
                                    // this error was thrown from our function override above.
                                    // so we send a useful message to the user
                                    return {
                                        status: "GENERAL_ERROR",
                                        message: "Seems like you already have an account with another method. Please use that instead."
                                    }
                                }
r

rp

12/16/2022, 10:28 AM
oh you need to
so copy the code from the other APi where you are calling the core to get the client_id and secret
and put it in this APi as well
a

Alen

12/16/2022, 10:29 AM
will this affect other third party auth ?
r

rp

12/16/2022, 10:30 AM
it will. But you can modify the user context only if the request has the tenantId input. If it doesn't then things will continue to work the way it used to
a

Alen

12/16/2022, 10:31 AM
Ok got it.
One more doubt, it was from Wilson's side. Is there any way to figure out if any employee from the tenants side has been removed, as there will be supertokens session available right, so we would like to restrict those users.
r

rp

12/16/2022, 10:37 AM
removed as in the user has been deleted or just removed from that tenant's org?
a

Alen

12/16/2022, 10:37 AM
Like yeah if the users are removed from the org
r

rp

12/16/2022, 10:38 AM
hmm. So at that time of removing them from the org, you could loop through all the user's session and call the revokeSession function on them
and then this would log them out when they do a next refresh
a

Alen

12/16/2022, 10:39 AM
Ok got it. Thanks.
r

rp

12/16/2022, 10:39 AM
one more thing, in the custom provider, can you show me the impelmentation for the getProfileInfo function?
a

Alen

12/16/2022, 10:40 AM
`getProfileInfo: async (accessTokenAPIResponse) => { const profile = await axios({ method: 'get', url:
https://7193f3e10df3d70f517937-us-east-1.aws.supertokens.io:5225/api/oauth/userinfo
, headers: { Authorization:
Bearer ${accessTokenAPIResponse.access_token}
, }, }); return { id: profile.data.id, email: { id: profile.data.email, isVerified: true } }; }`
r

rp

12/16/2022, 10:41 AM
right. So change the last part of
id: profile.data.id,
to be something like
id: profile.data.id + "|" + tenantId,
and you can get the tenantId from the userContext in the same way of how you get the client_id and secret
the reason to do this is so that if a person signs into a different tenant using their same SAML login, it will treat them as different users.
from the userContext
a

Alen

12/16/2022, 10:44 AM
Sorry , I misunderstood, thanks.
The email is coming like this, we would like to fetch the email address of user.
r

rp

12/16/2022, 11:41 AM
. Can you logout the profile object in getProfileInfo function?
a

Alen

12/16/2022, 11:49 AM
yeah I'm able to logout and login to same account
so it gets updated on supertokens user dashboard
r

rp

12/16/2022, 11:54 AM
Right but related to the email issue, can you console log the profile object? In the getProfileInfo function
a

Alen

12/16/2022, 11:54 AM
sure
data: {
    raw: {
      id: '1dda9fb491dc01bd24d2423ba2f22ae561f56ddf2376b29a11c80281d21201f9',
      email: 'jackson@example.com',
      firstName: 'jackson',
      lastName: 'jackson',
      'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier': 'jackson@example.com'
    },
    id: '1dda9fb491dc01bd24d2423ba2f22ae561f56ddf2376b29a11c80281d21201f9',
    email: 'jackson@example.com',
    firstName: 'jackson',
    lastName: 'jackson',
    idHash: 'e47ade86ba357f1041be45f8477f5b790309b3e7',
    requested: {
      client_id: '5283edb8634c7ca6c0431a7049cacf0fedba31ef',
      state: '74d99b0c7d3f94f1ec290',
      redirect_uri: 'http://localhost:4200/signup',
      tenant: 'alen1',
      product: 'Blocksurvey',
      scope: []
    }
  }
r

rp

12/16/2022, 12:21 PM
So you do set the email to
profile.data.email
which is
jackson@example.com
in this case
so it should make the user have that email ID
a

Alen

12/16/2022, 12:22 PM
but you asked me to override the email value right. `getProfileInfo: async (accessTokenAPIResponse) => { const profile = await axios({ method: 'get', url:
https://7193f3e14ef517937-us-east-1.aws.supertokens.io:5225/api/oauth/userinfo
, headers: { Authorization:
Bearer ${accessTokenAPIResponse.access_token}
, }, }); console.log(profile); return { id: profile.data.id, email: { id: profile.data.id + "|" + tenantId, isVerified: true } };`
r

rp

12/16/2022, 12:24 PM
oh no. Overrde the
id
value:
return {
  id: profile.data.id + "|" + tenantId,
  email: {
    id: profile.data.email,
    isVerified: true
  }
};
a

Alen

12/16/2022, 12:24 PM
Ok got it.
Also one quick help. Can you help me how to separate the flow for thirdparty and this saml flow. `authorisationUrlGET: async (input) => { input.userContext.request = input.options.req.original; let request = input.userContext.request; if (request.query.tenant && request.query.product) { let tenant = request === undefined ? "" : request.query.tenant; let product = request === undefined ? "" : request.query.product; const profile = await axios({ method: 'get', url:
${config.supertokensConfig.connection_url}/recipe/thirdparty/tenant/config?thirdPartyId=${product}&supertokensTenantId=${tenant}
, headers: { 'api-key': config.supertokensConfig.api_key, }, }); let client_id = profile.data.config.client_id; let client_secret = profile.data.config.client_secret; input.userContext.client_id = client_id; input.userContext.client_secret = client_secret; return await originalImplementation.authorisationUrlGET(input); } },`
r

rp

12/16/2022, 12:27 PM
so if
if (request.query.tenant && request.query.product) {
is not true, you should just call the original implementation
a

Alen

12/16/2022, 12:31 PM
I had tried this, but if you see this signinup call for google auth, query params are being added which is for saml.
r

rp

12/16/2022, 12:36 PM
yea do thats a frontend issue
so add those query params only if the thirdpartyid is related to saml
a

Alen

12/16/2022, 12:54 PM
Thanks, its fixed now.
Hopefully, we will be going live with SAML by next week. Thanks for your support.
r

rp

12/16/2022, 12:59 PM
Nice!