OAuth now supports PKCE

Hey everyone! :wave: We released an extension to our OAuth capabilities known as PKCE. With PKCE, you can securely complete the OAuth flow without having to store a client_secret in the application, enabling you to securely use OAuth from mobile, desktop, or single page applications!

Using PKCE is as easy as sending the code_challenge parameter in the Authorize request. Check it out and let us know if you have any questions!

1 Like

I’m having trouble understanding how PKCE can be used in mobile applications. It seems like it still requires a custom server application to handle the response via the redirect URL. How do I get the token down to the client from this custom server application? Seems like I’m back to square one. My use case is a mobile application that allows users to create mobile orders. They need access to the API resources, but I can’t store the API secret key in the app code. My next idea is to use PKCE but it seems like I would have to spin up a custom server to perform the authorization, receive the response, store the code verifier, etc (all of the things from the requirements section of this page: https://developer.squareup.com/docs/oauth-api/receive-and-manage-tokens). Is this true, or am I missing something?

@crocboy, thanks for your interest in PKCE! I’m the PM at Square for PKCE.

You’re correct that PKCE doesn’t change the redirect portion of the OAuth flow, it just removes the need for an application to remove a client secret. The way mobile (and desktop) applications generally handle this is by spinning up a small webserver on 127.0.0.1:<some_port> and catching the redirect there. iOS and Android also have the ability to register application specific URLs that when opened will open a specific app (in your case, your app).

Google’s Documentation describes the alternatives pretty well Note they call out deprecations for certain mechanisms, but that is about their sdks and not the OAuth spec as a whole.

I’d love to chat more about your application and how PKCE may work for you, if you’re interested DM me!

1 Like

Thanks Square for releasing PKCE!

I’m finding a few points about the PKCE documentation confusing, so hope you don’t mind me asking a few questions:

  1. In the initial oAuth PKCE flow, how can I do the ObtainToken API call using authorization code to get my first access token, without having to reveal the Application Secret? The doco for ObtainToken doesn’t disclose any support for the PKCE flow as far as I can see? I could proxy it, of course, but hoping not to do that, for obvious security reasons. (I understand it’ll be necessary to redirect the oAuth callback/“Redirect URL”, no issue)

  2. Similarly, when using ObtainToken with refresh token, how can we use ObtainToken without needing to reveal our App secret?

  3. The PKCE documentation states that the refresh token will only work once; does that imply that a new refresh token will be supplied as part of the refresh process? Just to get a feel of the intention, is the shorter refresh token life mentioned 30 days or more?

  4. Similarly, perhaps less importantly, RevokeToken also requires Application Secret - can this be done without revealing app secret?

Sorry for the 100 questions! if this is too much for here, feel free to delete and we can discuss privately. And apologies if I missed anything in the doco!

My use case is a server based app, running on servers I don’t control. Cheers!

@BrianC Hello!

Thanks for diving in, happy to answer.

In the initial oAuth PKCE flow, how can I do the ObtainToken API call using authorization code to get my first access token, without having to reveal the Application Secret? The doco for ObtainToken doesn’t disclose any support for the PKCE flow as far as I can see? I could proxy it, of course, but hoping not to do that, for obvious security reasons. (I understand it’ll be necessary to redirect the oAuth callback/“Redirect URL”, no issue)

When you are using PKCE, you call Authorize with a code_challenge parameter (this is standard for PKCE, and is usually some kind of random string you sha256 encode). Then, when you call ObtainToken you do not pass in an application secret, and instead pass in the code_verifier which is the plaintext of whatever your code_challenge was.

Similarly, when using ObtainToken with refresh token, how can we use ObtainToken without needing to reveal our App secret?

You can set the grant_type to “refresh_token” and you won’t need to pass in a client_secret if the refresh_token was originally granted via a PKCE flow.

The PKCE documentation states that the refresh token will only work once; does that imply that a new refresh token will be supplied as part of the refresh process? Just to get a feel of the intention, is the shorter refresh token life mentioned 30 days or more?

Because the PKCE-issued Refresh Token doesn’t require a client_secret, we have a few additional safety mechanisms for those refresh tokens: They can only be used once, when you redeem it you’ll get a new RT back with the new AT; they also expire after 90 days.

Similarly, perhaps less importantly, RevokeToken also requires Application Secret - can this be done without revealing app secret?

Currently, you cannot revoke without supplying the client_secret, but we’re still in beta and would love feedback around that, and what the desired use case would be!

I think that covers your questions, but don’t hesitate to reach back out! We can also connect on the buildwithsquare slack if you’d like something a little more realtime, just let me know!

Thanks for such a rapid and thorough response! Now that I see your answers, they were fairly obvious; what threw me off was that they weren’t mentioned in the API documentation yet (presumably because PKCE is still beta).

Overview of the use case for RevokeToken:
I’m working on a app-let that installs as a module into a larger billing system that is self-hosted and for which I don’t control the security, other than mandating SSL. The idea is to use PKCE so that the module doesn’t include my Application Secret; as the servers that run this system could be completely insecure.

I can see two/three use cases:

  1. user simply wants to log out of Square for some fandangled reason, and know that their tokens are revoked and all is safe; this is particularly important in that customer information is available via the tokens (eg: saved customers, saved cards, purchases, etc) in an age of EU GDPR and associated rules.
  2. security is compromised and the tokens are stolen somehow, and user wants to be certain both the access token and refresh token are invalidated
  3. subcase of the above: the app is copied to a new site, or they somehow lose partial control of the tokens in the database. This is a non-malicious scenario that could still cause problems accidentally.

I’m not sure these use cases are particularly strong, especially given that the workaround of having a small central RevokeToken serverlet is available, and since Best practice notes recommend keeping the tokens encrypted when at rest.

I’m sure you’ve thought of this and it’s likely problematic, but a Webhook notification of a token refresh could also be used to tighten security. If we got a webhook notification of a token refresh that wasn’t ours (presumably from the state, or SHA-256 of the state) the app could have an aneurysm involving emails and alerts. (not sure if this is even workable)

Thanks again!
Brian

postscript: I’m sure you’ve thought of this already, but, my preference would be for a PKCE RevokeToken to revoke my PKCE token and leave the other tokens working. The use PKCE case here is a semi-public site with a problem reuiring token destruction, contrasting against my hypothetical retail outlet use of tokens, which has no problems. I want to disable the semi-public token, whilst leaving my outlet running without interruption. Also, often outlet POS setup is difficult and fiddly, involving coordinating with vendors, so an interruption wouldn’t be brief. I know this is a departure from the current usage of RevokeToken, which revokes ALL tokens regardless, and I understand there are implications to work through (eg should the clientsecret RevokeToken then revoke all PKCE tokens as well? Is PKCE RevokeToken here essentially being used as a “logout” mechanism? Best wishes!

The reasons we are needing this are the same. I don’t want my application secret in the plugin and need a way to revoke. I don’t quite understand why such strict security in the revoke endpoint with the authorization header. It would seem that app ID and token would be sufficient to revoke.

1 Like