Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Add session renewal or an iFrame AuthorizationRequestHandler implementation. #68

Closed
someone1 opened this issue Aug 13, 2018 · 12 comments

Comments

@someone1
Copy link
Contributor

Right now, if my token provider only gives out short lived tokens (e.g. 5 minutes), I'd have to initiate a new redirect flow every time I want to renew the token to keep the user session alive. This forces me to break the user's experience and redirect/reload my app every 5 minutes! Ideally, there'd be a mechanism I could use to renew the token without initiating a redirect flow, which is all that seems to be provided from this library. I should note that I'm coming at this from the context of a SPA for which I know RFC 8252 doesn't directly apply (a SPA is not a native app, but both are public clients!) but know this library is designed to work with SPAs and even has a React example.

I guess I'd like clarification on how I can keep the user session alive without having to perform a redirect flow every time I need to refresh the session. I have coded my own implementation of an iFrame provider that implements the AuthorizationRequestHandler class to shoehorn this functionality into this library, but think it belong here to allow the use of prompt=none background/hidden refreshes for tokens where my OpenID Provider/iDP are aware of a user's session and consent status. Alternatively, could you provide an example of how we could keep a session alive with the current features provided by this library? Does implementing the OpenID Connect Session Management Draft make sense for this library?

Side note:
Google still recommends using the implicit flow for SPAs, and in fact, you cannot use a PKCE exchange with Google on a SPA (though your comments for other issues seem to show that Google knows better!) Is this something you can clarify or maybe have addressed internally at Google?

@brockallen
Copy link

Is this something you can clarify or maybe have addressed internally at Google?

And once they've done that, I encourage them to lead the charge at the spec committee making changes and recommendations there as well. I'd love to see a formal explanation of how code flow makes security better for SPAs. Up to now, that has not been shown.

@someone1
Copy link
Contributor Author

someone1 commented Aug 13, 2018

I do not intend for this to become the battleground of implicit vs PKCE in SPAs. I opened a question on Security Exchange on the topic and am open to discuss it there. In the post I do mention an article that gives merit to code flows over implicit (specifically, the unintended leakage of the token in browser history) and the article itself lists other sources on the topic. I believe PKCE further improves the code flow in a SPA (well, at least enables it!) in addition to the HTTPS whitelist redirects that validates the client. If there is (currently) no demonstrable value to it, I do prefer it as a defense-in-depth mechanism, if you'll give me the liberty of calling it that.

My purpose for this issue is to see if we can achieve what other libraries such as damienbod/angular-auth-oidc-client refer to as a "silent refresh" for tokens, and since I use Google OIDC tokens for authentication currently, pushing my agenda of allowing the use of PKCE in SPAs which is not currently supported by Google.

EDIT:

I just wanted to clarify that I agree with your comment, @brockallen, and in no way meant to be argumentative in my reply. I'd love for there to be more guidance/clarity on this specific topic.

@tikurahul
Copy link
Collaborator

Thanks for the feature request. I am in the process of adding support for the implicit flow as I mentioned here.

I hope that helps more clients out of the box.

@WilliamDenniss
Copy link
Member

WilliamDenniss commented Aug 13, 2018

Right now, if my token provider only gives out short lived tokens (e.g. 5 minutes), I'd have to initiate a new redirect flow every time I want to renew the token to keep the user session alive. This forces me to break the user's experience and redirect/reload my app every 5 minutes! Ideally, there'd be a mechanism I could use to renew the token without initiating a redirect flow, which is all that seems to be provided from this library.

Is there a reason not to use the code flow with a longer-lived token in this case?

"Ideally, there'd be a mechanism I could use to renew the token without initiating a redirect flow" really sounds like the use-case refresh tokens solves to me.

@WilliamDenniss
Copy link
Member

What follows is my own personal opinion.

Google still recommends using the implicit flow for SPAs, and in fact, you cannot use a PKCE exchange with Google on a SPA (though your comments for other issues seem to show that Google knows better!) Is this something you can clarify or maybe have addressed internally at Google?

That page pre-dates SPAs substantially, so I'm not sure if I agree with the premise of your statement ("still recommends"). I'm not aware of specific guidance for SPAs.

And once they've done that, I encourage them to lead the charge at the spec committee making changes and recommendations there as well. I'd love to see a formal explanation of how code flow makes security better for SPAs. Up to now, that has not been shown.

Can a RFC 8252 flow work for a SPA? i.e. can the app open the browser (the actual browser with cookies, URL bar, etc), and receive a URI redirect? I've not tried to be honest.

Conceptually the way SPAs behave feels more like a native app than a web site (no shared cookie state, no URL bar), and the code flow is required for native apps...

@someone1
Copy link
Contributor Author

someone1 commented Aug 13, 2018

@tikurahul - That's awesome about implicit flow but that's not related to what I'm asking for here. I'd like to use the code + PKCE flow to get short-lived access tokens and silently refresh them in the background. Right now, only a redirect handler is offered, I was hoping we could add an iFrame handler so that a token could be obtained without redirecting the user who may be mid-session but in need of a refresh. I also do not intend to request a refresh token as I'd like to minimize any exposure to the user.

@WilliamDenniss - To be more explicit, the SPA is already hosted on a web server and in a web browser, so "can the app open the browser and receive a URI Redirect" isn't really applicable - or rather the answer is a roundabout yes.

[what follows is a rough description of the flows]
With implicit flows, the user loads the app and is then redirected to the AS/IDP to give permission to the app for a certain RS, and the result is redirected to a whitelisted URI for that app (remember, we are a SPA hosted on the web already) that is https protected with the access token in the url fragment. Code + PKCE works in this context as well, where instead of the access token being returned in the redirect, an authorization code is returned instead and a POST from the app containing the code + PKCE verifier to receive the access token is performed.

A SPA is capable of performing both flows but the RFC is written targeted towards native apps. Although it's not formalized anywhere, there are suggestions (from comments made by @tikurahul and authors of sources I've previously linked to) that the merits of PKCE seem to apply to public clients in general, not just native apps.

The way this library is currently written, if a user had previously granted permission to a client, and the client does not have the ability to securely store a refresh token (as is the case with a SPA or any javascript based web app), then the user must be redirected to the AS/IDP before going back to the app so the client can get the token required. Any refreshes must be handled the same way mid-session. In the case of an application that wants to limit the user's exposure to security issues, I'd opt not to receive a refresh token and rely on short-lived access token instead. This way, if a user doesn't log out to kill the session/refresh token, and the app was unable to "time-out" the user due to a tab close (or some similar event), any potential leak that may have happened during the user's session would be limited to a short-lived access token, with no refresh token left active for a potential bad actor to use.

I guess my intended use-case of using code + PKCE over implicit stems from comments made by authors of Oauth related products/services that suggest we use the code + PKCE flow instead of the implicit flow for SPAs, and most point to the AppAuth libraries as the defacto implementation of the spec in order to get this done. There are some use cases for which this specific library doesn't seem well suited for but, IMHO, fall under the package's scope and isn't too far off from supporting (e.g. adding an iframe handler in addition to the existing redirect handler). In my app's use-case, users must reauthenticate on every new session to my app, but as long as they're actively using the application their session won't expire - this is achieved by using short-lived access tokens that are silently renewed as long as the app is in active use.

I hope that makes sense!

@WilliamDenniss
Copy link
Member

To be more explicit, the SPA is already hosted on a web server and in a web browser, so "can the app open the browser and receive a URI Redirect" isn't really applicable - or rather the answer is a roundabout yes.

So this is true when you visit the SPA in a browser, but it's not true if you add that SPA to your home screen and access it that way, right? In the latter case it's not being rendered in a general purpose browser (as evidenced by the lack of URI bars, and the fact if you open a link outside of the SPA, it will open in the browser app), but rather it's treated more like a native app.

Are you solving for both environments, or just the former? If the former, does the distinction of "SPA" change anything, i.e. can you just say "website" instead of "SPA" and everything would be the same?

I was hoping we could add an iFrame handler so that a token could be obtained without redirecting the user who may be mid-session but in need of a refresh

Is this "iFrame handler" defined in an OAuth spec? If not, then it's likely out of scope for AppAuth.

As you've found, the implicit flow requires a full-page redirect to get a new token. So would the code flow, if the refresh token was similarly time-bound. So really, if you want to provide a nice user experience to such users, longer-lived tokens are needed (regardless of "flow").

@someone1
Copy link
Contributor Author

Yes, you can replace SPA with "website" and everything remains the same. When you say launched from a home screen, are you implying a PWA? That's not what I'm getting at here and is not an intended mode for my application (all data is considered private and short-lived, a user MUST login for every session with the website so a PWA is not applicable here). Whether the user uses a desktop or mobile device, the mode of accessing the website will always be via a browser.

I guess really the library as-is could support iframe redirects, though the extra steps of tracking responses must be done by the application itself. You'd pass in your own LocationLike for an iFrame (or even a popup!) to the RedirectRequestHandler constructor along with a AuthorizationNotifier and setup a redirect that utilizes postMessage to send the response back to the parent to complete the flow. The entire thing needs careful implementation and would ideally be done by a library package meant to accelerate this process following best practices (as this package does) but maybe it makes sense to create a new package that wraps this one that implements the different modes? I guess this package even stops short of generating the PKCE code/challenge which is left to the developer whereas the Android/iOS counter parts do more for the developer than what this package does.

I misspoke when I said an iframe implementation needs to exist alongside the redirect handler - really the iframe (or popup) implementation would utilize the redirect handler but would do the extra steps of implementing it correctly/securely. Sort of like convenience implementations of common use-cases that are still sensitive to careful implementation.

@tikurahul - if you feel you'd rather leave the sensitive implementation of using an iframe's or popup's window.location on the redirect handler to the developer instead of providing it via this package, feel free to close this issue. I'd also like to know why Google doesn't support the PKCE flow for web clients if you have any insight to that!

@brockallen
Copy link

brockallen commented Aug 13, 2018

Is this "iFrame handler" defined in an OAuth spec? If not, then it's likely out of scope for AppAuth.

OAuth2 does not preclude it, and OIDC specifically adds prompt=none to formalize it.

Conceptually the way SPAs behave feels more like a native app than a web site (no shared cookie state, no URL bar), and the code flow is required for native apps...

Implicit is designed to limit the ability to renew access tokens to the user's browser session. Code flow leads to refresh tokens, which allows for renewing access tokens beyond that browser session (given that it's a public client). This is the main "pandora's box" security concern for code flow in the browser, IMO. I'd love for the spec committees to get involved with addressing this. I posted a few months ago to the list on this exact topic.

What's not clear is why code flow is superior from a security standpoint for a browser-base client. I've seen the arguments, and they all revolve around developer convenience and how the iframe approaches don't feel so modern.

@tikurahul
Copy link
Collaborator

@someone1 You are correct. This library is meant to solve the low level plumbing meant to make the kind of flows you are talking about easier. So you could pass an instance of LocationLike that belonged to an iframe. Such an implementation would go beyond the scope of this library like you have identified.
The RedirectRequestHandler is very versatile.

I am not sure I understand what you mean when you say Google does not support web clients. It does. AppAuth-JS will get out of the box PKCE support soon. I just wanted to provide similar interfaces which can help with substitution around the how of generating sha256s. I just have not gotten to it yet. There are a couple of forks that have also added this on top of the existing library. The AppAuth-JS implementation is newer than its corresponding iOS and Android implementations. I don't have higher level APIs yet, but they too are coming. Having used this library in a number of projects now, I have an API that I am happy with.


I also need to reiterate that this library will not and need not support every OAuth2 and OIDC RFC. I don't have any intention of doing so. If there is a feature that's missing, feel free to fork the library and add that feature. This library however will make that process hopefully easier. This is a volunteer run, 20% project like the rest of AppAuth-* projects.

@someone1
Copy link
Contributor Author

@tikurahul First and foremost, I am truly appreciative and grateful of the fact that you are supporting this project the way you are.

RE Google & PKCE - You cannot use PKCE on anything but with iOS or Android application types. If you try and use PKCE with Web application type, it will expect the client_secret on the code/token exchange step. This is when I use the Credentials Console to create a new oauth client and select the "Web application" Application type. This is the only application type that allows me to enter HTTPS redirect URIs which is what would be required for a browser-based PKCE flow. I opened support cases with Developer support and was told to open the issue I linked to previously - were you able to get this working with the web application type, and if so, how?

@tikurahul
Copy link
Collaborator

Yes, that is a distinction Google makes when you choose the web client. But the client_secret in question is just a secret in name only. Google knows that web clients are public clients and that they cannot keep any secrets. Nothing in the protocol is predicated on the client_secret being a secret. I suggest that you just send client_secret.

All I can say is that, it’s unfortunate that Google makes this distinction based on the client type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants