Skip to main content

Hi all. Newbie to RC here, so perhaps I am doing something wrong. But...

In a browser (Firefox) using javascript and the RC js SDK, I am trying to implement the OAuth2 3 legged flow using PKCE and "top frame setup" (see Top frame setup on the JS SDK page). FYI I have successfully implemented the "Popup setup" described on the same page.

In the Top frame setup, when my redirectUri landing page calls rcsdk.login(loginOptions) the SDK throws an error with message "code_verifier required". It looks to me like the SDK is not sending the code_verifier when making the authorization_code request to the RC Auth server and so the RC Auth servers response is a 400 bad request.

I am not sure how the SDK would know the value of the code_verifier as I believe it was generated on the main page when the loginUrl was created and I don't see how in this scenario the landing page SDK is going to have that info. So, perhaps PKCE is not possible using the top frame setup?

I have attached in a zip including simplified versions of the main page and redirectUri page html/js for your viewing pleasure.

rcOAuthPkce.zip

Any advice or insight would be appreciated.

Thanks. -- David

From what I can see, you are trying to re-login from the redirect.

The long answer (with some explanation) is
The rcOauthCallbackEx.html route will be called by the ringcentral auth server (assuming you have set up the route properly in the ringcentral developer app and you are running your app as a server)
You do not need to re-login from the rcOauthCallbackEx.html page. All you need to do is to call the RingCentral.SDK.handleLoginRedirect() function which will get the verification code and pass it to the main window which initiated login

The short answer is
Replace

var rcsdk = new RingCentral.SDK({
server: "https://platform.devtest.ringcentral.com",
redirectUri: "YOUR_REDIRECTURI_HERE",
clientId: "YOUR_CLIENT_ID_HERE",
});

var loginOptions = rcsdk.parseLoginRedirect(window.location.hash || window.location.search);
rcsdk.login(loginOptions)
.then(function(ret) {
console.log("RC Login() return:");
console.log(ret);
}).catch(function(e) {
alert("Login error " + e.message);
});

With

RingCentral.SDK.handleLoginRedirect()

in your rcOauthCallbackEx.html file and try things out once


A small suggestion.
Pushing your code on github/bitbucket/gitlab or any such platform and sharing the link would be more helpful for us instead of attaching a zip with the code


Hi Yatin.

Thank you for taking the time to look at my question and posting a reply. I tried your suggestion and the redirectUri.html page received an error that opener is null on SDK.ts 57. That is b/c the flow I am implementing (as described on the JS SDK page) is the 'Top frame setup' not the 'Popup setup'. So on the original web app page (call it Page1), instead of getting the loginUrl and then calling loginWindow() (as is done for the Popup setup) this flow gets the loginUrl and then *navigates* to the loginUrl using the same browser window. So there is no popup or new page and thus there is no window.opener since, by design, we navigated away from Page1 to the loginUrl instead of opening a popup or new tab.

In the Popup setup (as I am sure you know), the only thing handleLoginRedirect() does is perform a postMessage() to the window.opener passing back the query params so that the call to loginWindow() resolves and Page1 can call login() passing the returned loginOptions. Login() will add the code_verifier (if set) to the token request. As I mentioned, I have implemented the Popup setup successfully, but for various reasons thought the Top frame setup might be more useful in my situation.

In the 'Top frame setup', if we weren't using PKCE, I think the redirectUri should do a login and then reload Page1 which will likely try to login to RC again and be successful (I think) since the access and refresh tokens will be stored in the browser local storage. But with PKCE we created the code verifier and code challenge in Page1 and so the redirectUri.html does not have it.

Hmm, so I am thinking that Page1, after creating the code verifier and code challenge must save the verifier to the browsers local storage. Then, in the redirectUri page, we must read the verifier and pass that to login (looks like it can be passed). Once the login is resolved, we can redirect to Page1 which will try to login to RC and find we are logged in - I hope.

But, unfortunately, I do not have access to the code_verifier (do I?) as it is embedded in the SDK.

Thanks again for your suggestion, it helped me dig deeper into things.

-- David


Hi @David S
This is interesting.
Sorry for missing out on the use case.
I now understand what you are trying to do.
Let me try to run this locally and see if I can find the cause and the solution to this.
I am glad you went through the SDK and saw how we post internally over the socket.

I will get back on this once I try this out
Please revert with the solution if you are able to find that in the meanwhile so that it can help others looking for a similar thing :)


On further analysis, I found the root cause
This is happening because you are creating a new instance of the SDK on the redirect page.
If you can share the same instance of SDK from the index.html and the redirect page, things will work
The SDK will save code_verifier when making the login call
can be seen here
https://github.com/ringcentral/ringcentral-js/blob/2bc7829c17fe196bfe7fb38d3752e8163dff67fc/sdk/src/platform/Platform.ts#L289

but because on the redirect page, a new SDK instance is used, it does not know what was the code_verifier

Hope this helps


Hi again.

Ok, so in the main page, I was able to get the code_verifier from rcsdk and save it to the browser local storage. Then in the redirect page, I was able to read the cv, add it to the loginOptions and call login(). Once login() resolved, I reloaded the main page and when I clicked the login button, it found we were already logged in and no OAuth was needed 🙂. Of course, you can have the redirect page reload the main page and the main page could also try to log in automagically. But I leave that as an exercise for the reader.

Updated code is here on Github as a gist.

BTW, It would be good if RC added some info about PKCE to the JS SDK page.

Thanks to Yatin for the time and comments.


Thanks for sharing the code and details
Glad to be able to help :)


This is part of the SDK readme now
https://github.com/ringcentral/ringcentral-js/tree/master/sdk#top-frame-with-pkce-setup


Thanks, @David S for helping us identify this


Reply