Genesys Cloud - Developer Community!

 View Only

Sign Up

Expand all | Collapse all

Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

  • 1.  Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

    Posted 20 days ago

    I have written a web application that I use with many Genesys Cloud orgs. It uses the JavaScript PSDK, and summarises license usage.

    I recently updated the application to use loginPKCEGrant instead of loginImplicitGrant to authenticate the user (using SSO). This happens when the app is loaded in the browser, and the user is redirected to Microsoft for SSO, and one of the following occurs:

    • If they haven't recently (in the same browsing session) authenticated to Genesys Cloud, they are prompted for their username and password and MFA, and then they are prompted for which Genesys Cloud org they want to use. And they are redirected back to the app where the PKCE stuff completes and they then have a valid token for the selected org.
    • If they have recently (in the same browsing session) authenticated to Genesys Cloud using a different Genesys Cloud application, it skips asking for their credentials and they are simply asked for which Genesys Cloud org they want to use. And they are redirected back to the app where the PKCE stuff completes and they then have a valid token for the selected org.
    • If they have recently (in the same browsing session) authenticated to Genesys Cloud using the same Genesys Cloud application, it skips asking for their credentials and the org, and redirects them back to the app where the PKCE stuff completes and they then have a valid token for the same org they originally selected.

    Since I want to use this app with multiple orgs, I'm looking for a way to get the 3rd scenario above to prompt the user for the org.

    When I was using Implicit Grant, I could do a fetch() to replicate the loginImplicitGrant redirection, and include "&prompt=login" in the the URL, and that would cause SSO to ask them for the org. Then when the user was redirected back to the app they had a valid token.

    But this doesn't work with PKCE Grant due to the PKCE challenge stuff.

    So what I'd like to request is that the LoginPKCEGrantOptions class is enhanced to support "prompt:login", and then include that in the URL parameters when the redirection occurs?

    Thanks.


    #PlatformSDK

    ------------------------------
    Nick Tait
    Genesys Consultant
    ------------------------------


  • 2.  RE: Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

    Posted 20 days ago
    Edited by Jerome Saint-Marc 20 days ago

    Hello,

    Do I understand correctly that you were directly calling the login url (in case of Implicit Grant) using fetch (at least on first trigger - before getting the redirect with access_token and then possibly calling loginImplicitGrant), and not making use of the loginImplicitGrant method both times (first and on redirect)?

    If yes, I don't think that adding support for prompt:login as LoginPKCEGrantOptions (and in the loginPKCEGrant) would be enough.

    If you call the loginImplicitGrant or loginPKCEGrant method from the "same" page/tab (I mean where you have loaded the Platform API JS library and performed a login flow once), even if you're not persisting settings (i.e. setPersistSettings to true), the library will attempt to check if there is a token (global variable), test it and use it if it is successful. So if your two orgs are in the same region (url not changing), the test of the token will be successful (on the first org - even if you are trying to point to a different clientId).
    If I were to add prompt:login support in loginImplicitGrant, and if you were calling the loginImplicitGrant both times, instead of fetch (if I understood your login process correctly), you would have the same behavior (I mean 3rd scenario not prompting them for an org).

    The Implicit Grant flow that you experience "works" because you are calling the login url via fetch() and therefore skipping the logic applied in the loginImplicitGrant method (that checks an existing token).

    So I think adding prompt:login in LoginPKCEGrantOptions wouldn't really change this, because calling loginPKCEGrant method would do the same thing than loginImplicitGrant, i.e. checking if there is an existing token stored (either as global variable or also in local storage if setPersistSettings with same app name has been set in your other apps).

    I can see to add the prompt:login in a future version of the SDK for Implicit Grant and PKCE Grant. But as written above, I don't think that will be enough.

    To get similar behavior, I think you'd need to skip the "first" loginPKCEGrant method call. And as PKCE implies a two-step process with code challenge and code verifier, have some code to manage this. Just theoretical as I don't know how your app is built and what/where you would need to change these things.

    I had made the generation of code verifier and computation of code challenge available as methods on the ApiClient class. The code verifier would need to be saved in session storage (as it is needed for the second part of the PKCE process - and to be extracted by the loginPKCEGrant method).

    So for first call, possibly something like:

    const apiClient = platformClient.ApiClient.instance;
    let codeVerifier = apiClient.generatePKCECodeVerifier(128);
    let codeChallenge = await apiClient.computePKCECodeChallenge(codeVerifier);
    sessionStorage.setItem(`genesys_cloud_sdk_pkce_code_verifier`, codeVerifier);
    // then fetch of the login url for PKCE
    // with client_id (new clientId), redirect_uri, code_challenge (equal to codeChallenge vairable computed above), response_type: 'code', code_challenge_method: 'S256', prompt: 'login'

    And then, being able to invoke the loginPKCEGrant method on the redirect (which contains the code query parameter).

    If you can, try this and let me know how this goes.

    As said, I can still add the prompt:login support in future versions of the SDK, but I don't think that'd be enough for your flow. The logic needed is probably closer to the code I have described above. Not having similar test environment and SSO (and not having your web app), it is a bit difficult to guarantee it will be enough.

    Regards,



    ------------------------------
    Jerome Saint-Marc
    Senior Development Support Engineer
    ------------------------------



  • 3.  RE: Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

    Posted 20 days ago

    Hello,

    I have exposed prompt auth parameter in the loginImplicitGrant and the loginPKCEGrant methods (through opts parameter). It is available in version 241.0.0.

    But as explained in my previous post, if I correctly understood your use of fetch for the Login Implicit Grant flow, you'llk probably have to do something similar to the code I put in my post.

    Regards,



    ------------------------------
    Jerome Saint-Marc
    Senior Development Support Engineer
    ------------------------------



  • 4.  RE: Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

    Posted 17 days ago

    Hi Jerome.

    Thanks so much for creating the new version to test this with...

    By the way all your assumptions based on how I'm using this were right. Also just FYI I'm using setPersistSettings(false).

    You were 100% correct that including prompt:login in the opts passed into loginPKCEGrant isn't sufficient to force the user to log in due to loginPKCEGrant checking for a saved token before performing the redirection.

    So I tried the workaround you provided above, and almost worked... In fact I believe the workaround itself is perfect, but it seems that there is something funny going on with Microsoft SSO when you are using PKCE and include prompt=login in the URL? The reason I say that is because I was trying to work out what I needed to do by comparing the redirection URL being fetched by my application with the redirection URL used by the Platform API Explorer when you tick the Prompt for Login box, before realising that the API Explorer exhibits the exact same issue:

    1. The browser redirects to https://login.mypurecloud.com.au/oauth/authorize?client_id=...&response_type=code&redirect_uri=...&code_challenge=...&code_challenge_method=S256&state=...&prompt=login
    2. The Genesys Cloud login page saying "Log in with your account:" and the Microsoft icon is presented to the user:
    3. The user clicks on the Microsoft icon to login with SSO.
    4. At this point the browser should be redirected back to the application, but instead the user is presented again with the the Genesys Cloud login page saying "Log in with your account:" and the Microsoft icon. i.e. GOTO Step 2.

    I'm sure this used to work OK, but maybe the API Explorer has only recently been updated to use PKCE instead of Implicit login, and that has caused this to stop working?

    I wondered whether this could be a problem with our SSO, but unfortunately I don't have any orgs using other Entra ID providers to test with.

    So I think I'll continue using your workaround, and hope that at some stage the loop that is exhibited by API Explorer gets resolved, at which point my app will hopefully work too?

    Nick.

    P.S. This is the API Explorer Prompt for Login box:



    ------------------------------
    Nick Tait
    Genesys Consultant
    ------------------------------



  • 5.  RE: Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

    Posted 17 days ago

    Hello Nick,

    "Also just FYI I'm using setPersistSettings(false).". If you are opening a new tab/window, that could possibly work calling loginImplicitGrant or loginPKCEGrant twice (still with the issue with you are facing now). But if it is from an existing tab that already loaded the lib and logged in on a different org, it will take a saved token stored as global variable.

    "I'm sure this used to work OK, but maybe the API Explorer has only recently been updated to use PKCE instead of Implicit login" I don't know the exact status but yes, they are in the process of migrating the login to PKCE Grant on API Explorer.

    I understand you may not know all the orgs in advance, but it could be interesting to see what happens if you provide the provider and org auth parameters when you fetch the url (if it allows to skip this page you see or not). If the SSO provider has been created recently, I think the value of the provider is now the id of the SSO provider in GC configuration (was done to allow multiple SSO providers of the same type). If it is a legacy SSO provider config, then it should be among the values as it is in the doc ("okta", "adfs", "salesforce", "onelogin", "gsuite", or "ping").

    Regards,



    ------------------------------
    Jerome Saint-Marc
    Senior Development Support Engineer
    ------------------------------



  • 6.  RE: Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

    Posted 16 days ago

    Hi Jerome.

    Thanks for the ideas.

    I had a bit of a play with including (in fetch URL parameters) org and provider, and also target, but it didn't change anything as far as the behaviour I'm seeing.

    I also tried experimenting with changing the app to check when the page loads if sessionStorage.getItem('genesys_cloud_sdk_pkce_code_verifier') == null and if so, include "prompt:login" in the opts passed to loginPKCEGrant, but that also ended up in an authentication loop, which kind of supports my theory that the back end (performing the authentication) can't handle prompt:login with PKCE? If so I'm thinking that the only way to get this to work is to get the back-end fixed? And hopefully if that happens my app with the current workaround (thanks to yourself) will start working?

    Thanks,



    ------------------------------
    Nick Tait
    Genesys Consultant
    ------------------------------



  • 7.  RE: Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

    Posted 16 days ago

    Hello,

    I don't have SSO in my test environment. So I unfortunately can't try myself.

    Something I didn't think about, as you mentioned that you have setPersistSettings(false) -> I am not saying this will change outcomes in your test scenario. But to simplify the code, and possibly avoid the use of fetch (and the code I provided in my previous post), to only use loginImplicitGrant/loginPKCEGrant on every page load or redirect. You could just reset the access token which is stored as global variable, and then invoke loginImplicitGrant/loginPKCEGrant (with or without prompt:login) -> apiClient.setAccessToken(null)

    The test on existing access token will "fail" and should then call the function like if it was a first load.

    In your scenario, I was not clear if you are changing the clientId. If yes, I assume it should bring you to a login page (even without prompt:login). If not, probably not (unless you still make use of prompt:login).

    Regards,



    ------------------------------
    Jerome Saint-Marc
    Senior Development Support Engineer
    ------------------------------



  • 8.  RE: Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

    Posted 14 days ago

    Hi Jerome.

    I tried setAccessToken(null) before calling loginPKCEGrant and it does achieve the same result as what I had been referring to as 'fetch'. But because I'm using Typescript, setAccessToken(null) also resulted in an error being reported due to setAccessToken expecting a string parameter, not null. So I think I'll stick with 'fetch' for now...

    And just to correct the record, my 'fetch' was actually location.replace(authUrl).

    Also I'm using the same Client ID (with multiple orgs), and so as you predicted, in the situation where I'd recently authenticated with the same app and without prompt=login, SSO redirects back to the app without prompting for the org. (And when including prompt=login, I end up with the authentication loop described above.)

    I'm happy to park this issue for now if you like? I'd like to wait and see if Genesys resolves the API Explorer authentication loop (when ticking the 'Prompt for login' option), and then see if my issues go away? (I expect they will.)

    Thanks for your help, and have a good Christmas! :-)



    ------------------------------
    Nick Tait
    Genesys Consultant
    ------------------------------



  • 9.  RE: Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

    Posted 14 days ago
    Edited by Jason Kleitz 14 days ago

    Hi Jerome.

    Thanks for those suggestions. I can confirm that using setAccessToken(null) before loginPKCEGrant achieves the same thing as the fetch (i.e. causes loginPKCEGrant to redirect rather than using a cached token). Although one minor complaint is because I'm using Typescript, an error is reported due to the function expecting a string argument, not a null. So for now I think I'll stick with fetch.

    Also I'm using a single Client ID for my application (with access to multiple orgs), and as you suspected that means that in 'scenario 3' (i.e. redirecting for authentication shortly after having authenticated for the same application), without prompt=login, SSO redirects back without prompting for the org. (And with prompt=login, gets stuck in the authentication loop.)

    I'm happy to park this issue for now if you like? I'd be keen to retest the behaviour after Genesys (hopefully) resolves the (same) authentication loop with API Explorer (when ticking 'Prompt for login' option)?

    Thanks for your help, and have a great Christmas!



    ------------------------------
    Nick Tait
    Genesys Consultant
    ------------------------------



  • 10.  RE: Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

    Posted 14 days ago

    Hello Nick,

    I am not following your last statements.

    "I'd be keen to retest the behaviour after Genesys (hopefully) resolves the (same) authentication loop with API Explorer (when ticking 'Prompt for login' option)?"

    It probably has nothing to do with API Explorer, as you are facing the same with the SDK and your app when you use prompt:login. The two are just following the authorize and token urls to be used for OAuth PKCE login.

    It is either something specific to PKCE Auth flow (and in that case, it might be worth reporting it to Support, at least for tracking or for investigation - not mentioning SDK or API Explorer but the OAuth PKCE Grant flow) or to your Multi-SSO setup.

    Regards,



    ------------------------------
    Jerome Saint-Marc
    Senior Development Support Engineer
    ------------------------------



  • 11.  RE: Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

    Posted 14 days ago

    Hi Jerome.

    I was assuming that the same issue that I have with API Explorer with Prompt for login ticked would be experienced by anyone using Microsoft SSO. But you are correct we probably need that assumption confirmed.

    I'll raise a support case as per your suggestion.

    Nick.



    ------------------------------
    Nick Tait
    Genesys Consultant
    ------------------------------



  • 12.  RE: Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

    Posted 14 days ago
    Edited by Nick Tait 14 days ago

    I've raised a support case (#0003941903) for API Explorer PKCE SSO loop.

    I suppose the other question I have is whether the Typescript definition for setAccessToken should be updated to allow null to be passed as a parameter?

    setAccessToken(token: string | null): void;

    Or alternatively create a separate method?

    clearAccessToken(): void;


    ------------------------------
    Nick Tait
    Genesys Consultant
    ------------------------------



  • 13.  RE: Enhance loginPKCEGrant method to support "prompt:login" option (in LoginPKCEGrantOptions)

    Posted 13 days ago

    I'll probably add something like clearAccessToken. So it doesn't affect existing typescript code from other people modifying from string to string | null.
    But this won't be done immediately. We are working on some other builds issues and I'll be out of office starting next week. If I can push something before I leave (so it is taken into account in next builds), I'll do it. Otherwise it may be in first days in January.

    Regards,



    ------------------------------
    Jerome Saint-Marc
    Senior Development Support Engineer
    ------------------------------