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

Handle payment server token expiration more gracefully #1694

Open
lmorchard opened this issue Jul 8, 2019 · 3 comments

Comments

Projects
None yet
2 participants
@lmorchard
Copy link
Member

commented Jul 8, 2019

Follow-up to #881

Payment server gets a token with a short expiration. That means the user could more likely be in the middle of something when it expires.

Currently, we sometimes bounce back to the settings page on the content server when this happens. Other times, we just report errors. This should be smoothed out into something with better UX - automatic token refreshes? something else?

@lmorchard

This comment has been minimized.

Copy link
Member Author

commented Jul 10, 2019

This might be blocked by #1696 if we want a resolution here to be that the payment app silently requests to refresh its short-lived token and retries the operation. (i.e. The user attempts to submit payment to subscribe, but they took longer than the token lifetime and so the request fails unless we get another token)

In fact, we might want some product / UX thinking on this one, too...

@lmorchard

This comment has been minimized.

Copy link
Member Author

commented Jul 10, 2019

Adding needs:product and needs:ux labels. Here's a rephrasing of the problem:

When the user arrives at either a product payment page or the subscription management page, they're sent in with an access token. That access token allows the payment pages to make API calls. The API calls accomplish whatever the user's there to do - e.g. pay for a new subscription, update their current card, cancel subscriptions, etc.

For security reasons, that access token has a short life time - which currently defaults to 15 minutes. After that life time expires, it's no longer usable to make API calls and the user needs to somehow acquire a new one. In terms of UX & product, that means if the user takes longer than the access token life time to complete a task, that task will fail with an error.

So, what can we do about this in terms of UX & product? Depending on how #1696 works out, maybe we can just request a new access token? Otherwise, we might need some UX finesse to walk the user through starting over with their task, which seems less than happymaking. (e.g. if the user's in the middle of typing out a credit card number, they'd need to do it again after a page refresh)

We might be able to tweak the access token life time, too - though that has security implications and I seem to recall we wanted to make it shorter, in fact.

@lmorchard

This comment has been minimized.

Copy link
Member Author

commented Jul 11, 2019

Got a positive answer on refreshing the token in #1696 - so I think this de-escalates from needing any product or UX decisions. I think we can just push refreshing the token into the invisible background and not have to surface it as a concern to the user.

shane-tomlinson added a commit that referenced this issue Jul 12, 2019

feat(payments): Use PKCE to access the payments page.
This is a bit strange, but here we go.

We aren't doing a traditional OAuth flow here where we start at the RP (payments page)
to set up `state` and PKCE parameters. To do so cleanly would require support for
`prompt=none`, which we do not yet have. See #640, PR #1150.

Instead, we secure the flow and prevent CSRF by relying on cookies.
We set up state and the PKCE parameters on the content server, then send
the params to the content-server backend to store in an HTTP only cookie on
accounts.firefox.com scoped to /payments-pkce.

Still on the content server, we then generate an OAuth code using the
generated state/PKCE params, and redirect to the payments page.

The payments page gets the OAuth code/state out of the URL.
It then fetches the state/PKCE params from the content-server
by making a GET request to /payments-pkce. The content-server
ensures the request comes from the payments domain, reads
the cookie, and then returns the PKCE/state info.

The payments server now has all the stuff it needs to trade
the OAuth code for an access token. It makes the call to the
OAuth server's /token endpoint with the code from the URL,
and the state and PKCE parameters returned from the backend.

A refresh token is also returned enabling fetches of new
access tokens if the current one expires.

issue #1696
issue #1694

shane-tomlinson added a commit that referenced this issue Jul 12, 2019

feat(payments): Use PKCE to access the payments page.
This is a bit strange, but here we go.

We aren't doing a traditional OAuth flow here where we start at the RP (payments page)
to set up `state` and PKCE parameters. To do so cleanly would require support for
`prompt=none`, which we do not yet have. See #640, PR #1150.

Instead, we secure the flow and prevent CSRF by relying on cookies.
We set up state and the PKCE parameters on the content server, then send
the params to the content-server backend to store in an HTTP only cookie on
accounts.firefox.com scoped to /payments-pkce.

Still on the content server, we then generate an OAuth code using the
generated state/PKCE params, and redirect to the payments page.

The payments page gets the OAuth code/state out of the URL.
It then fetches the state/PKCE params from the content-server
by making a GET request to /payments-pkce. The content-server
ensures the request comes from the payments domain, reads
the cookie, and then returns the PKCE/state info.

The payments server now has all the stuff it needs to trade
the OAuth code for an access token. It makes the call to the
OAuth server's /token endpoint with the code from the URL,
and the state and PKCE parameters returned from the backend.

A refresh token is also returned enabling fetches of new
access tokens if the current one expires.

issue #1696
issue #1694
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.