Continue Discussion 38 replies
May 2019

oktadev-blog

Bjorn Harvold

Great article Aaron!

May 2019

oktadev-blog

Adam Schueller

Very useful! Our security team is NOT happy with using OIDC in SPAs because of the lack of security using implicit flow.

“Start Using the Implicit Flow with PKCE in JavaScript Today” → looks like a typo, you mean ‘Authorization Code Flow’ right?

May 2019

oktadev-blog

Aaron Parecki

Thanks! You’re totally right, not sure how that slipped by me! Will push a fix shortly, thanks!

May 2019

oktadev-blog

Mikee

Well explained! How do you protect APIs from replay attack? Is it built in OKTA? Thanks!

May 2019

oktadev-blog

Aaron Parecki

Thanks! Do you mean replay attacks in obtaining the access token? Authorization codes can only be used once, which prevents that attack.

May 2019

oktadev-blog

Mikee

Thanks for the answer. Actually I am currently doing a research. Our team needs to implement a way to handle replay attacks

May 2019

oktadev-blog

Aaron Parecki

There are a couple of different replay attacks, so I’m not quite sure which you are referring to. It would be worth reading this document which describes many of those attacks as well as others. https://tools.ietf.org/html…

June 2019

oktadev-blog

Chris Becke

https:/{yourOktaDomain}/oauth2/defalut/v1/auth is clearly a typo, and I think you need the authorize, not the auth, endpoint for this kind of thing: https://{yourOktaDomain}/oauth2/default/v1/authorize is whatI need or I get “http method is not supported by endpoint” errors.

June 2019

oktadev-blog

Aaron Parecki

Thanks, you’re right, I’m updating this with a fix. The full URL includes authorize, but in any case you should copy the values from your server’s configuration since depending on the type of Okta account you have, and whether you’re using the default authorization server, you might have a different URL as well.

June 2019

oktadev-blog

Chris Becke

The only guidance I know to build URLs is Composing Your Base URL, and while ‘default’ might change to an authServerId I don’t see any option to look urls up in the servers configuration.

June 2019

oktadev-blog

NitNeKing

Documentation update. You note that you’ll need to grab the client id. I believe this needs to be set in : var config = {
client_id: “0oak2hglgrKY60Lhw0h7”,
redirect_uri: “http://localhost:8080/”,
authorization_endpoint: “”,
token_endpoint: “”,
requested_scopes: “openid”
};

Note: Set your own client_id :slight_smile:

June 2019

oktadev-blog

Aaron Parecki

Yes, I left it blank in the example so that you can fill it in with your own.

June 2019

oktadev-blog

NitNeKing

Very helpful article. I had one question after implementing the demo (thank you). In the diagram of PKCE flow referenced here: https://developer.okta.com/… , there is one box titled ‘Client App (vue.js)’. I’m assuming you mean this is the browser (client side code)?

The code from the demo is all client side code, so in my head I had it fitting into the diagram under this ‘Client App (vue.js)’. If that is indeed the case, where is the backend for the SPA in this flow? If the SPA is making backend API calls, would you pass the access token obtained (as seen in your demo) as a bearer token to the backend API? If so what checks/validation should be done.

Again, thank you for putting this together.

June 2019

oktadev-blog

Aaron Parecki

Yes exactly. In that diagram, the example is a Vue.js client-side app. This post doesn’t use a framework, and instead uses plain JavaScript.

In both cases, the assumption is that the client-side app will be calling other API backends (not drawn in that diagram).

You would use the access token obtained in the flow as a bearer token sent to the API, preferably in the HTTP Authorization header. The client-side app should not do any validation of the access token itself, as that is entirely the job of the backend API.

June 2019

oktadev-blog

NitNeKing

Perfect. Any recommendations on best practices on how/where to store the access token once obtained? Cookie? Browser storage? And regarding token validation on the backend, any articles or examples on how the backend should perform this validation? I see its a JWT token, so I can decode and obtain user data that would driver perms/logic. But I take it there should be some validation done every time. Thanks for the quick response!

June 2019

oktadev-blog

Simon

Thanks you! Very helpfull post.
Do you have any recommandations on refresh tokens or silent authentication with this flow?

June 2019

oktadev-blog

Aaron Parecki

That’s usually done as part of an OpenID Connect flow as well, some info on that here: https://www.scottbrady91.co…

June 2019

oktadev-blog

Aaron Parecki

That page in the docs is not very clear, but it starts with your Issuer URI which you can find in your Okta dashboard.

June 2019

oktadev-blog

Jeff Lambros

So, we can use a public client (no secret) with the Authorization Code flow w/PCKE in our SPA applications to address the fact we can’t keep a secret. My concern is using the public client, not requiring a secret, to perform the Refresh flow. Don’t we have the same problem not being able to keep the Refresh Token ‘secret’ also?

June 2019

oktadev-blog

Aaron Parecki

Yes, most authorization servers will not issue refresh tokens to JavaScript apps, because they are more risky. With public clients, the refresh token is extremely powerful, since it can be used without a secret, so many providers eliminate this risk by just not issuing refresh tokens to any kind of public client.

June 2019

oktadev-blog

Jeff Lambros

Thanks for the response Aaron. With a short-lived Access Tokens and no Refresh Token, how do we keep the user from having to authenticate again to get a new Access Token?

June 2019

oktadev-blog

Aaron Parecki

There are generally two ways, both rely on the user having an active session at the authorization server, which is key to the security of both. Either you can send the user back through the whole authorization code redirect flow again (which happens so fast they won’t even see it), or you can use the hidden iframe technique that’s part of OpenID Connect to do that flow invisibly.

July 2019

oktadev-blog

Vladimir SD

In the video, at minute 14, you talked about a way using the Authorization flow where the token does not even get sent down to the browser, just the session cookie.
Can you point me to some examples of how this could be done in Spring Boot?

btw, great video, how you guys do more of them!

July 2019

oktadev-blog

Micah

With Spring Boot, if you use the OAuth2 client and a templating engine like Thymeleaf, the token will only ever be on the server. This post uses Spring Boot in that way. It layers in JPA and MySQL, but it’s using OAuth2 & OIDC at it’s core.

July 2019

oktadev-blog

Vladimir SD

If the token is only on the server how do you handle multiple web server besides sticky sessions?

July 2019

oktadev-blog

Yang Wang

Is it safe to store the pkce_state and pkce_code_verifier in localstorage? What’s the likelihood of someone being able to access it and intercept the authorization_code before our app does?

September 2019

oktadev-blog

aaronpk

That’s about the best you can do. There’s always a possibility something can steal data out of LocalStorage, but as long as you’re taking all the precautions against XSS, and have a strong content security policy to limit the number of third-party JS libraries on your site, that’s about the best security you can get in a browser. There are some good tips on browser security from OWASP here: https://cheatsheetseries.ow…

October 2019

oktadev-blog

NitNeKing

Hi Aaron,

Thanks for this article and example code. It is extremely useful. Periodically a few of our users actually get to the point in the code where an ‘Invalid State’ is thrown from this line:


if(localStorage.getItem(“pkce_state”) != q.state) {
alert(“Invalid state”);
} else {

I’m trying to understand when this would happen. We store the ‘pkce_state’ that we generated locally and is used to verify the response coming back from Okta so that it matches with the same call to the authorization server (that we asked for the auth code). Instead of throwing the alert would another option be to clear local storage and start the flow over?

December 2019

oktadev-blog

Faris Shomou

Hi,

Im getting this error : {“errorCode”:“E0000022”,“errorSummary”:“The endpoint does not support the provided HTTP method”,“errorLink”:“E0000022”,“errorId”:“oaez_eq3XLlTPS195AcIPysdQ”,“errorCauses”:}

Thanks,
fshomou@hotmail.com

March 2020

oktadev-blog

Nathan Blair

There’s no such thing as safe storage, client-side, and very rarely, server-side. Regardless of platform. This PKCE method is, at best, security through obscurity. And due to its convoluted extra steps, it will receive little adoption. By suggesting the use of libraries, what we’re really saying is “you don’t need to ACTUALLY understand the vulnerabilities your app may be exposed to, just trust this entity!” And…we’ve seen how even the biggest firms drop the ball on this stuff. Open source or not, any library will eventually experience a leak. And that means BIG problems for your application security.

What would be most secure is not storing any tokens at all, short of living in memory (which even then, I think may have potential vulnerabilities). When a user needs to access secure resources, they’re always presented with a prompt to login. Since its 2020, websites should be using existing OAuth federated providers and remembering credentials for these providers shouldn’t be an issue. At the very least, the attack surface has been limited now to the vulnerability of the credentials being exposed from a UA/browser, instead of CRSS/XSS/CORS/BFSS/KSLDFSS/ASS vulnerabilities of cookies, web storage, or maybe even indexedDB?

Until then, implicit flow is the closest we’re going to get to not relying on insecure heavy token or client secret storage. So I’d say its far from dead.

March 2020

oktadev-blog

aaronpk

The storage problem with JS apps has nothing to do with PKCE. PKCE protects the data sent in the redirect, which is a different attack surface than stored tokens.

Put yourself in the shoes of the authorization server issuing the access token. If you send an access token to the application by sending it in an HTTP redirect, you have no idea whether the application has actually received that access token, or what may have stolen it via the redirect in the process. For example, this browser extension will show you any sites that you log in to that are using the Implicit flow: https://github.com/oktadeve… It turns out that any extensions you have installed could already be siphoning off access tokens without your knowledge.

By using PKCE, the authorization server issues a one-time code in the redirect, and the application has to confirm receipt of it by making the separate POST request for an access token. If someone were able to steal the code from the redirect, they wouldn’t be able to use it to get an access token thanks to the PKCE mechanism.

Now, once the app has the access token, whether it got it from the implicit flow or using PKCE, the problem is now how it can store it in a secure way. This problem exists both with the implicit flow and with PKCE, and you’re right that it is mostly an unsolved problem with browsers. But, PKCE solves a different, more important problem, so it is useful.

I explain this more in this video: https://www.youtube.com/wat…

March 2020

oktadev-blog

Nathan Blair

I think what the PKCE solution allows could be done with just enforcing a state nonce as well, and allows for one less round trip. Encode the code challenge, embed it in the state (or even just add the code verifier/challenge to the implicit flow as parameters), have the server send back the access token and the state and/or code challenge. Send the access token in addition to the decrypted state nonce and/or code verifier in all API requests. Server side, it only means checking one additional entity. Effectively, the access token is your proof authentication, the additional parameter becomes your proof of authorization.

I could probably have explained that better but it’s still early lol. I agree that there’s a vulnerability issue with the implicit flow though. But at least (if done correctly) access tokens have a short lived expiration time. There’s no way to renew them unless an extension was able to authenticate on your behalf, and at that point, I don’t think it’s an OAuth issue as a browser/HTTP(S) issue.

It may be time we re-architect-ed our approach to secure access of APIs. Insomuch that we move forward with the notion that there’s no such thing as secure storage, short of, at best, living in memory.

There’s this notion of: the user wants to experience the convenience of being logged in even after they navigate away from the page or close a tab/window. But maybe there’s a radically different approach where we end up with a more secure solution. I don’t know what that is, but I think the person that figures it out is going to make the world a much better place :grin:

March 2020

oktadev-blog

Morné Niemand

@disqus_TDZbDnPyrN did you ever find a good method for storing the access token client side? cookie? session storage?

April 2020

oktadev-blog

bebo

what about refresh token stored in httoOnly cookie with path and domain fixed to some “login” endpoint? then even with csrf there’s no way to use that refresh token for accessing anything other than relogging in user, especially if access token response is stored only in memory

May 2020

oktadev-blog

Justin Meyer

Where can I read more about the hidden iframe technique?

September 2020

oktadev-blog

Gabriel Sroka

I forked the code above and added OAuth for Okta:
https://github.com/gabriels…

December 2020

oktadev-blog

D.Nikhil Teja

"If you’re building a JavaScript app that is served from a dynamic server, such as a Spring Boot backend with an Angular frontend, or an ASP.NET backend with a React front-end, then you can keep all of the OAuth exchange and token management inside the backend, never exposing it to the JavaScript front-end, and avoid all the risks inherent in managing tokens in JavaScript."

The referenced article “Spring Boot backend with an Angular frontend” still uses implicit flow with Angular. Am I missing something?

December 2020

oktadev-blog

Matt Raible

The Build a Basic CRUD App with Angular 7.0 and Spring Boot 2.1 does not use implicit flow. It uses authorization code flow with PKCE because that’s the default when you create a SPA app on Okta. However, it does use the word “implicit” in its callback URL, so I can see why it might be confusing.

This article points out that it’s better to do all your authentication flows on the backend. My Angular + Docker with a Big Hug from Spring Boot post provides an up-to-date example of that. In particular, see Combine Your Angular + Spring Boot App into a Single JAR.