Closed
Bug 1490357
Opened 7 years ago
Closed 7 years ago
Investigate how Auth0 Flows work
Categories
(Data Platform and Tools :: General, enhancement, P1)
Data Platform and Tools
General
Tracking
(Not tracked)
RESOLVED
FIXED
People
(Reporter: chutten, Assigned: chutten)
References
Details
It is clear from Auth0's documentation[1] how to add a login flow to a client application and determine aspects of the user from it... but not how to integrate that with the Aggregates Service.
The key points appear to be that it is the Aggregates Service who needs to know if the user is authenticated, but it's the frontend that is the only thing that can authenticate the user.
Let's farm this problem around and see if we can scare up some experts who might have some sage advice for us.
[1]: https://auth0.com/docs/libraries/auth0js/v9
Assignee | ||
Comment 1•7 years ago
|
||
:mreid is going to see if :wlach has some words of wisdom for how to do this. ni? for his learnings.
Flags: needinfo?(mreid)
Comment 2•7 years ago
|
||
Seems like a nifty little library. The real question for me is how is authentication set up on the aggregates service? Is that set up to require auth0 authentication already?
Flags: needinfo?(mreid) → needinfo?(chutten)
Assignee | ||
Comment 3•7 years ago
|
||
It isn't, yet. :frank may have taken a look at it already (or longitudinal may have been eating his brains), but I know too little about how the service is served (what is Flask, anyway) to really know where to look for how-to guides.
Flags: needinfo?(chutten) → needinfo?(fbertsch)
Comment 4•7 years ago
|
||
No, the service does no authentication. From first blush we assumed it would be something like:
1. Frontend has the user login to auth0, acquires token
2. Frontend sends the token to the service with each request
3. Service verifies token with auth0, serves appropriate data
I get that from here: https://auth0.com/docs/quickstart/backend/python
There's some more info about JWKs here: https://auth0.com/docs/jwks
Flags: needinfo?(fbertsch)
Comment 5•7 years ago
|
||
I don't see any reason why this wouldn't work, but my understanding is that it's considered bad form to store authentication credentials client side, since it leaves them vulnerable to being stolen by a cross site scripting attack. See, for example:
https://dev.to/rdegges/please-stop-using-local-storage-1i04
One alternative would be to have some kind of proxy server in between which manages the user's session and makes requests on their behalf:
https://github.com/alexbilbie/alexbilbie.github.com/blob/master/_posts/2014-11-11-oauth-and-javascript.md
Comment 6•7 years ago
|
||
(In reply to William Lachance (:wlach) (use needinfo!) from comment #5)
> I don't see any reason why this wouldn't work, but my understanding is that
> it's considered bad form to store authentication credentials client side,
> since it leaves them vulnerable to being stolen by a cross site scripting
> attack. See, for example: ...
Just to clarify: I'm not saying "we're not allowed to store the credentials client side", I'm just linking to my understanding of the issues involved. It might be that the trade-off of implementation difficulty vs. security makes the proposed solution acceptable (though I'd get another opinion or two before proceeding).
Comment 7•7 years ago
|
||
Traditional implementations with e.g. Django must have _something_ stored on the client, or else they would be asked to login again on every request. Any idea what they are storing? Could we:
1. Have the client send username/pass over the wire to the service
2. Have the service verify the client info
3. Have the service store the client token, and then create a mozaggregator-only token it sends back to the client
4. The client then uses the mozaggregator token on every request until timeout
That would eliminate the possibility of a XSS attack, or any attack (except those that target the service) grabbing the Auth0 token.
Comment 8•7 years ago
|
||
(In reply to Frank Bertsch [:frank] from comment #7)
> Traditional implementations with e.g. Django must have _something_ stored on
> the client, or else they would be asked to login again on every request. Any
> idea what they are storing? Could we:
>
> 1. Have the client send username/pass over the wire to the service
> 2. Have the service verify the client info
> 3. Have the service store the client token, and then create a
> mozaggregator-only token it sends back to the client
> 4. The client then uses the mozaggregator token on every request until
> timeout
>
> That would eliminate the possibility of a XSS attack, or any attack (except
> those that target the service) grabbing the Auth0 token.
Typically django uses session information which is sent with every request, this session information is typically stored on the client as a set of cookies. I'm not sure of all the details, but typically there are various mechanisms set up by default (e.g. csrf protection: https://docs.djangoproject.com/en/2.1/ref/csrf/) which make it very difficult to hijack another user's session in the event that the token is compromised.
Roll-your-own approaches like the above make me kind of nervous, the details of this sort of thing are notoriously difficult to get right. Now that I think about it, is there any way we could set up the aggregates service to handle and serve the login and session details? That would simplify things a great deal, and would remove the need for most of the client-side auth0 interactions.
Comment 9•7 years ago
|
||
It wouldn't be great to have the service serving web pages, because it's used as an API endpoint. That would render the release data unavailable to anyone except through the TMO dashboards, unless they make their own webpage that serves the login.
If we want to avoid a roll-your-own, then we should find the simplest Auth0 server integration and accept that we will now have to deploy a server for the telemetry-dashboard. Unfortunately this is much more work than we originally anticipated.
Comment 10•7 years ago
|
||
(In reply to Frank Bertsch [:frank] from comment #9)
> If we want to avoid a roll-your-own, then we should find the simplest Auth0
> server integration and accept that we will now have to deploy a server for
> the telemetry-dashboard. Unfortunately this is much more work than we
> originally anticipated.
The other option is just accepting the compromises of storing the auth0 token locally. This might be fine for all I know, there seem to be varying opinions on how bad a practice it is. It probably partly depends on the complexity of your application and what it interacts with, in this case the aggregates dashboard is not that complex.
I think at this point we've probably enumerated all the viable options, I wonder if the best thing to do at this point might be an RRA with infosec: https://infosec.mozilla.org/guidelines/risk/rapid_risk_assessment That would probably make us a little more comfortable with whatever we decide to go ahead with.
Comment 11•7 years ago
|
||
Okay let's be clear about the options here:
1. Client logs in using traditional Auth0 login, stores token locally, sends token along with requests (easiest)
2. Client logs in through service, service creates service-only token, client sends that token along with requests (more difficult no Auth0 token stored on client)
3. Deploy server along with dashboards, client logs in through server/Auth0, which sends authenticated requests to service (lots of work)
Does that sound right Will?
Comment 12•7 years ago
|
||
(In reply to Frank Bertsch [:frank] from comment #11)
> Okay let's be clear about the options here:
>
> 1. Client logs in using traditional Auth0 login, stores token locally, sends
> token along with requests (easiest)
> 2. Client logs in through service, service creates service-only token,
> client sends that token along with requests (more difficult no Auth0 token
> stored on client)
> 3. Deploy server along with dashboards, client logs in through server/Auth0,
> which sends authenticated requests to service (lots of work)
>
> Does that sound right Will?
Yup, this sounds good. There's a bit more to fill out for the RRA, follow the link and you'll see. :)
Comment 13•7 years ago
|
||
(In reply to Frank Bertsch [:frank] from comment #11)
> Okay let's be clear about the options here:
>
> 1. Client logs in using traditional Auth0 login, stores token locally, sends
> token along with requests (easiest)
Commenting without having a greater understanding/context, but as InfoSec we try to discourage this approach, because of the concerns raised by :wlach in comment 5.
In saying that, this:
> It probably partly depends on the complexity of your application and what it interacts with, in this case the aggregates dashboard is not that complex.
is a valid statement as well. If this approach is chosen there are some steps which could be taken on the front-end (Django side), such as a implementing a restrictive content security policy (CSP) which, even if the Auth0 token is accessed via an XSS, could prevent exfiltration of it for further abuse.
Happy to discuss in an RRA.
Assignee | ||
Updated•7 years ago
|
Points: --- → 3
Comment 14•7 years ago
|
||
Hi all, just a FYI - as per :ulfr's suggestion, it sounds like :alm is best suited to perform an RRA about this. Therefore I am cc'ing him to this bug and also assigned the relevant RRA bug 1490827 to him.
Comment 15•7 years ago
|
||
I talked with kang after the RRA and he was able to provide us with some more details on how we would go about this.
What we are looking for is implicit grants, which will get us a scoped access key we can use with the API (as described with the TaskCluster example).
https://auth0.com/docs/api-auth/grant/implicit
To do this, changes will be required both on the dashboard side (for the authentication) and on the auth0 side (we need a configuration for the API here to properly scope the id_token/access token.
An example of how this can be configured in auth0 and added to the API can be found here: https://auth0.com/docs/quickstart/backend/django/01-authorization.
Once the access token has been provided by auth0 and verified by the API, this can be used to create a session for the user in the API.
Also, local storage is not explicitly required for this mode of operation (the tokens can be stored in js runtime/memory as well) but that means you will lose them on navigation away from the site. Most implementations we have like this store the id_token (which can be used to issue access tokens for the scoped API) in local storage.
Assignee | ||
Comment 16•7 years ago
|
||
From the looks of things I can request the access token directly and relay that up to the service without needing an id token at all. Some storage is required to verify the response's state matches the request's state... but since auth is quick enough maybe we can avoid storing the access token...
Anyhoo, seems as though investigation's mostly done and now we're into prototyping and implementation. Time to file moar bugz.
Status: ASSIGNED → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Updated•7 years ago
|
Product: Webtools → Data Platform and Tools
Updated•2 years ago
|
Component: Telemetry Dashboards (TMO) → General
You need to log in
before you can comment on or make changes to this bug.
Description
•