Closed Bug 1051808 Opened 10 years ago Closed 7 years ago

Add FxA OAuth support to basket

Categories

(Websites :: Basket, defect)

defect
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: pmac, Assigned: pmac)

References

(Blocks 1 open bug)

Details

User Story

Add FxA OAuth support to /subscribe and /user endpoints.

## Basic procedure

Instead of an FxA user sending a browserid assertion to a separate endpoint to get the user's basket token, they can just send an OAuth token. Basket will then verify the token using the FxA OAuth server[1] which will return the FxA ID of the user. Basket will use that to lookup the user, and if one is found, proceed with the subscription, or return the user's information.

[1] https://github.com/mozilla/fxa-oauth-server/blob/master/docs/api.md#post-v1verify

Attachments

(1 file)

We need to create a new API endpoint for use by the FxA dashboard page. The
description is as follows:

 /news/fxa-login
 method: POST
 fields: assertion
 returns: { status: ok, token: token } on success
          { status: error, desc:, code: } on error

 The handler for this API must:

 1: send the assertion to the FxA verifier, passing a required audience of
    https://basket.mozilla.org/ , and receive a "success" response
    (response.status === "okay")
 2: extract the user's FxA uid from the response
 3: locate an existing DB entry with the matching FxA uid
 4: if there is no matching FxA uid, return an error
 5: if there is a match, return the access token for the matching user
Product: Other Applications → Websites
Chris, I'm starting on this now. Do you have a link to some docs about the FxA verifier I'm to use and how I can test with it?
Flags: needinfo?(ckarlof)
Assignee: nobody → pmac
Status: NEW → ASSIGNED
After chatting today with Paul, we decided it would be more straightforward to make Basket a FxA service provider, meaning its API could be authenticated with FxA OAuth tokens for the logged in user. I've filed a bug on our OAuth server to track this: https://github.com/mozilla/fxa-oauth-server/issues/126
Flags: needinfo?(ckarlof)
User Story: (updated)
Summary: Add API endpoint to use Persona assertion to retrieve user's token → Add FxA OAuth support to basket
Any update on testing info. I've not heard back from seanmonstar on the github issue for a few days. I don't think this is a priority at present, so if that's the case we can just put this on the back-burner as it were and do other things until we're ready with this.
Flags: needinfo?(ckarlof)
Paul, we need to make some documentation on becoming an FxA OAuth service provider, and write some tools for service provider devs to easily obtain OAuth tokens for testing. You could do so now by interacting with our OAuth APIs, but I think some command line tools would be helpful here.

I don't want to "back burner" this too much, but let's focus on our other collaboration (bug 1062626) for the time being, and I be back in touch when we have the tools to make your dev process easier in this effort.
Flags: needinfo?(ckarlof)
We may be able to make more progress on this. In particular, we now have a command line tool to let you get an OAuth token for your own email address with the basket scope that you can test against your Basket server: https://github.com/mozilla/fxa-oauth-client
Hey pmac. Checking in on whether we're able to make any forward progress on this.
Flags: needinfo?(pmac)
On the FxA side we're definitely in a better position to move forward on this.  If you want to start trying out the OAuth integration, our dev environment now has a self-service console through which you can provision a client_id/client_secret pair, and that allows you to generate tokens for testing purposes:

  https://oauth-stable.dev.lcip.org/console/clients

(Note that you must login with an @mozilla.com address to access the console).
To clarify, Basket would be a service provider, not a relier, so it just needs a reasonable scope and testing instructions.
Indeed, although the console may still be useful to generate OAuth tokens for testing purposes.

Who or what will be the relier in this scenario? i.e. what thing is going to generate oauth tokens and submit them to this API?  Is it just a post-signup page on content-server?

:pmac there is some python code for verifying oauth tokens in the PyFxA module, which is sadly underdocumented at the moment (that's on my head to fix) but may help get you started:

  https://github.com/mozilla/PyFxA
  https://github.com/mozilla/PyFxA/blob/master/fxa/oauth.py#L162
> Indeed, although the console may still be useful to generate OAuth tokens for testing purposes.

Possibly, but our OAuth CLI (https://github.com/mozilla/fxa-oauth-client) was built to support FxA service providers during dev (i.e., an easy way for them to get an OAuth token for a user account with the necessary scopes without running a relier). 

> Who or what will be the relier in this scenario? i.e. what thing is going to generate oauth tokens and submit them to this API?  Is it just a post-signup page on content-server?

Yes, the idea was that it was some page on the FxA content server, likely post-signup verification.
Thanks for getting the conversation going again guys. I'm getting some pings from above about having journeys for Accounts be a part of the spring campaign. Is it at all reasonable to see this piece of the puzzle (the opt-in infrastructure work) getting done by March 15?
> Is it at all reasonable to see this piece of the puzzle (the opt-in infrastructure work)
> getting done by March 15?

Do you mean just the ability for basket to accept FxA-OAuth-authenticated requests, or do you also mean the post-signup opt-in page on the FxA side?

For the former, I can work with :pmac to integrate our existing support libraries on whatever timeline works well for him.  For the later, it will depend on how much of the previous UI and front-end work we can re-use (e.g. from https://github.com/mozilla/fxa-content-server/issues/992)
I think the former: basket to accept authenticated requests. 

Thanks, Ryan.
OK, here are some concrete notes on what this would look like.  The readinglist backend is a good example of how to do this in a python app, see e.g.:

   https://github.com/mozilla-services/cliquet/blob/master/cliquet/authentication.py#L58

Assuming you don't need any nuanced sub-permissions like "read-only", let's use OAuth scope "basket" to grant blanket access to this API.  Accepting such tokens is a simple matter of parsing them out of the "Authorization" header and asking our oauth server to validate them:

  import fxa.oauth

  # This defaults to production, but you probably want to start on the dev server
  client = fxa.oauth.Client(server_url="https://oauth-stable.dev.lcip.org")

  # Grab the token out of the Authorization header
  scheme, token = request.headers["Authorization"].split(" ", 1)
  assert scheme.lower == "bearer"

  # Validate the token and check for appropriate scope.
  # This will throw if things are not as they should be.
  res = client.verify_token(token, scope="basket")

  # You now have the user's FxA uid
  print res["user"]

What this *doesn't* get you is the actual email address associated with the account.  I assume you'll need this for setting up initial subscriptions.  There's a web API for it (https://github.com/mozilla/fxa-profile-server/blob/master/docs/API.md) but it's not exposed in PyFxA yet, so I'll add that to my short-term TODO list.
> For the later, it will depend on how much of the previous UI and front-end work we can re-use (e.g. from https://github.com/mozilla/fxa-content-server/issues/992)

Yep, something needs to use the FxA OAuth enabled Basket API!
OK, it sounds like we need a companion bug to scope and track the work on whatever-it-is that will call into this oauth-enabled API.

Ben, I guess you've got the most context on product requirements there.  Can you please file a bug or link an existing one underneath Bug 1041074?  I'll make sure we take it into consideration for upcoming FxA roadmap planning.
Sure. To clarify, what is the new bug scoping and tracking? (I got a little lost in all of the above).
Flags: needinfo?(pmac)
> what is the new bug scoping and tracking?

So IIUC, this bug is tracking the "backend" work of making basket accept FxA OAuth tokens, and we need an additional bug for the "frontend" work of actually interacting with the user and making FxA-authenticated calls into basket.

It sounds like this is most likely to involve work within fxa-content-server, to present subscription options during the sign-up flow.  But I've no context on the requirements there.
Blocks: 1140528
WIP API for access basic profile data in PyFxA: https://github.com/mozilla/PyFxA/pull/15
PyFxA v0.0.4 has been released with basic profile info support.  So you could now do something like:

  import fxa.oauth
  import fxa.profile

  # These defaults to production, but you probably want to start on the dev server
  oauth = fxa.oauth.Client(server_url="https://oauth-stable.dev.lcip.org")
  profile = fxa.profile.Client(server_url="https://stable.dev.lcip.org/profile")

  # Grab the token out of the Authorization header
  scheme, token = request.headers["Authorization"].split(" ", 1)
  assert scheme.lower == "bearer"

  # Validate the token and check for appropriate scope.
  # This will throw if things are not as they should be.
  res = oauth.verify_token(token, scope=["basket", "profile:email"])

  # You now have the user's FxA uid
  print res["user"]

  # And can fetch the corresponding email address
  print profile.get_email(token)
pmac ping.
Flags: needinfo?(pmac)
pmac: re-pinging. Can we talk about moving this forward? I think the front-end work can start while the back end goes forward in parallel. How can I help?
I got a test script to work using PyFxA and the dev console https://oauth-stable.dev.lcip.org/console/. This might take a while however just due to the volume of dependencies:

pyfxa
requests
responses
cryptography
PyBrowserID
hawkauthlib
six
unittest2
mock
pyasn1
enum34 
cffi 
webob 
traceback2 
argparse 
ordereddict 
pycparser 
linecache2

At least 2 of those are compiled, so we'll have to wait for IT to install them on all the machines in the cluster if they're not there already. I'll file a bug and let you know. I can get started on the changes in the mean time.
Flags: needinfo?(pmac)
Just to add context here, we wound up implementing a thin proxy in front of basket in order to add oauth support:

  https://github.com/mozilla/fxa-content-server/pull/2460/files

This should provide the basic functionality we need to move forward with the FxA frontend integrations, but let's also continue with adding native OAuth support to basket.
Basket is now on AWS using Docker and Deis, and is therefore in a much better position to complete this work. I'm just noting this because I plan to do this as I have time so that hopefully :rfkelly et al can retire the proxy service they're running from comment #26.
:pmac, are you still open to doing this?  It would be the one piece of functionality remaining in our fxa-basket-proxy service after we migrate all the event-handling stuff over to your SQS queue.
Flags: needinfo?(pmac)
Definitely. I'll add this back to my priority list.
Flags: needinfo?(pmac)
ni? myself to check on what APIs to call with the FxA bearer token
Flags: needinfo?(rfkelly)
I took a fresh look at this, and the code in Comment 22 still looks like the way to go here:


  import fxa.oauth
  import fxa.profile

  # These defaults to production, but you probably want to start on the dev server
  oauth = fxa.oauth.Client(server_url="https://oauth-stable.dev.lcip.org")
  profile = fxa.profile.Client(server_url="https://stable.dev.lcip.org/profile")

  # Grab the token out of the Authorization header
  scheme, token = request.headers["Authorization"].split(" ", 1)
  assert scheme.lower == "bearer"

  # Validate the token with oauth-server and check for appropriate scope.
  # This will throw if things are not as they should be.
  res = oauth.verify_token(token, scope=["basket", "profile:email"])

  # You now have the user's FxA uid
  print res["user"]

  # And can fetch the corresponding email address from the profile-server
  print profile.get_email(token)

This will unfortunately involve two round-trips to FxA, one to check the validity of the token, and one to get the email address to which it corresponds.  We can probably figure out a way to do all of that in a single request but it would involve blocking on engineering work on the FxA side.
Flags: needinfo?(rfkelly)
Commit pushed to master at https://github.com/mozmeao/basket

https://github.com/mozmeao/basket/commit/73ef44a1622704009297b43acd9e6f14b3e65a28
Fix bug 1051808: Add FxA OAuth

Support FxA OAuth headers for certain requests.
Status: ASSIGNED → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Support for FxA OAuth is now on all of our servers on the basket side. Didn't see a reason to keep it out of prod since no one is using it yet. Let me know if you run into any issues in testing against stage or prod.
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: