Very confused on passing login parameters

Let me introduce the problem and how I discovered Auth0.

We sell a thing you might call a network appliance. It is a smart gateway to embedded devices. One end serves a basic HTTP/websocket; we want to bump up security and add social integration.

You might have seen the problem already: we have multiple servers and users logged to one cannot be accepted in the other.

So my idea was to pass a custom JWT to the login page so I can encode an unique server id and use a rule to annotate the resulting user profile.

I’m having an hard time wrapping my head about the documentation. I found something about auth:params regarding Lock’s option object but it is unclear to me if I can put arbitrary parameters there. Besides, Lock somehow went modal instead of taking me to the hosted page. I want HTTPS and the green lock.

So I tried Auth-js. It has been surprisingly smoother. I managed to get my rule to reject the login as the server-id I was looking for was not there.
So I guess the ‘state’ isn’t really just a black blob as a security measure but it is actually arbitrary data? Even if it is, am I supposed to put such important information there?

I read the documentation again and again and while I had the impression ‘state’ could be arbitrary, the constant references to the attack vectors made me think it was really supposed to be… some kind of random blob? Better to leave auth0-js to generate it for me?

The state parameter according to the specification that defines it (OAuth2) is described as:

An opaque value used by the client to maintain state between the request and callback.

This implies that it may contain arbitrary data (although given it’s a parameter included in a URL query parameter the data it can contain is constrained in size). As you mentioned, the most common use of that parameter is as a CSRF mitigation for the client application redirection endpoint. The client application includes something in theory not guessable in the initial request and then it can validate that the response contain that same value as means to avoid processing responses that were not requested directly by the client application.

However, there’s nothing that prevents the state parameter to be used both as a CSRF mitigation and to also transport arbitrary data. This can be done by either including both the random component and specific data in the parameter itself and encoded as a single value or just by using the random component and keeping the specific data at the client application, but associated to the generated random component.

The above means that the state value should be treated as an opaque value by the authorization server which just receives it and then echoes it back without making assumptions or any processing on the value itself.

In conclusion, you can include arbitrary data in that parameter, but it’s not usual for that data to be processed by the authorization server (the rule here would be seen as part of the authorization server). Additionally, that parameter may be controlled by the end-user so making decisions on it may or may not be a security issue by itself depending on your exact situation.

If the only restriction is the fact that a user can only be logged in at a single server than receiving the server identifier from the client application despite the user being able to possibly control it may not be an issue as the user could manually try to select another server, but if they did they would still get constrained to a single server. If this is the case, you not have even need to pass a JWT, nonetheless, you may also consider trying a custom parameter instead of overloading state parameter; according to the docs, additional query string parameters would be available in a rule through context.request.query.

Thank you for your reply; it seems very exhaustive.
I come from a GPU computing background so I’ll need to re-read everything a few times before I assimilate the details.

Nonetheless, my understanding is I should leave the state alone and go with custom params.

The original plan involved query parameters but I was using Lock at the time. I don’t recall reading examples about custom parameters for auth0-js, nonetheless the auth0.authorize example reads:

webAuth.authorize({
  //Any additional options can go here
});

For some reason the ‘any’ always read as ‘any of the known parameters’ to me and I don’t recall example code using custom params from my mind.
I tried just appending the extra parameters to the url and it doesn’t seem to be working. Probably because my /authorize end up taking me to /login and something goes missing. So (in typescript) I just made the right thing instead:

    const params = {
        redirectUri: redirect
    };
    params'easyname'] = JSON.stringify(serverToken);
    this.auth0.authorize(params);

The data gets to the rule exactly as the documentation. Thank you again. I just got lost a bit.

I am very concerned about the security implications. While I am confident we are stepping up our security practices I wish I had the time, budget and skills to bring this to state of the art. For the time being, a shared-secret will have to suffice; I’m not proud of security through obscurity but if login-password still do I’ll be simply doing var hash = require('hash.js').sha512().update(magic).digest(); and a couple of comparisons as a validation.