Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
How to remove Set-Cookie from headers with REST implementation
  • Implementing some REST-like API's, my auth is leveraging simpleauth, in general things have been working fine in initial testing.  Running 1.5 currently

    Trying to cleanup up my response some, specifically the headers.  I want to remove the cookie info from the headers as most/all of the clients will not be utilizing cookies for passing info, instead just using the session id as a token to pass in header with each request.

    Pre-fuel days I would just set the Set-Cookie header to "" and payload would be removed from the response.  In trying that now it appears somewhere in the response chain its getting set.  I have traced all the way through and whenever spitting out the headers, even up till when they are sent it looks like no other headers sets are happening.  Somewhere though the cookie is being set after mine and seems to get passed along.  Doing a global search for 'Set-Cookie' returns no results.

    Anyone try anything similar before using simpleauth or other session auth/session handling?
  • HarroHarro
    Accepted Answer
    If you use sessions, the cookie get's set in the shutdown event, which calls the write() method on the session driver class, using an event callback.

    Your best bet is probably to overload the Session_Driver class in your app, convert the _set_cookie() method to a NOOP. the _get_cookie() method can already deal with getting the data from a POST or GET variable (used for example by swf based uploaders).
  • Thanks for the tip, worked like a charm.

    Using db for sessions, ended up overriding the Session_Db class, put a check in right at the _set_cookie call to see if session is a "REST" session for the user, if so, omit setting/sending cookie vals
  • Hey Harro,

    Quick follow up question since you mentioned the _get_cookie method, been continuing on with dev-work. To date in previous setup have had things setup where the API clients pass the "auth token", which is session id, in the headers.  The app would then look for a valid session in the db with that id, and load from there.

    In looking through code some looks like a couple touch points I can intercept at to load the session up.  Would it be recommended to put the login inside the db drivers read() function?
  • The session drivers should not be concerned with a "login", they deal with session data.

    If you stick the session id in the request header instead of in a cookie, it would be logical that you would use the _get_cookie() method to get it from the header instead of the cookie. If you just use the standard cookie format, then the rest can remain the same, the header value will be unpacked, the session id recovered, and the session loaded.
  • I was looking at putting logic in the Session_Db driver to only have logic that "if REST call, and cookie false, look for session_id in header, and try to load as usual instead of using ->key['session_id']".  I was worried I shouldnt be mucking with normal cookie setting and copying over to the ->keys array.
  • That is what I meant. The _get_cookie() method in the Session_Driver driver is the method that retrieves the session id from where it's stored (usually the cookie, hence the method name).

    Currently it supports cookie, GET variable, POST variable, but it shouldn't be too much effort to add a check for header data in there too. If you do that, then nothing else needs to change, and everything works transparently.

    What does your header look like? I can see if I can get this into 1.7.
  • Right now its just:

    X-Auth-Token=<session_id>

    Was from old implementation I am porting up to new fuel setup, think I modeled after some of the public cloud API's.  Premise is heavily mobile focused, dont want the mobile clients to deal with session/cookie stuff on their end, so just auth, get session token back, then pass on every call
  • I get that.

    Can you create a feature request for this at https://github.com/fuel/core/issues, with a short description and a link to this thread?
  • Yup, seen the notification. Thanks.
  • Hey Harro,

    Just merged in the 1.7 commits to try and get going that you just committed.  Getting error, wondering how implementation is done.

    I am getting the 'Session-id' header value picked up for the session_id token being passed over.  Problem is that it then always hits/fails on the "invalid general format" check:

                if (is_array($cookie))
                {
                    // cookies use nested arrays, other drivers have a string value
                    if (($this->config['driver'] === 'cookie' and ! is_array($cookie[0])) or
                        ($this->config['driver'] !== 'cookie' and ! is_string($cookie[0])))
                    {
                        // invalid specific format
                        $cookie = false;
                    }
                }
                else
                {
                    // invalid general format
                    $cookie = false;
                }

    Do we have to take the string session_id, and make a fake array() form of the cookie with that value so it gets returned to session driver and can do the db lookup correctly?
  • Hmm... Thought I implemented that, but it turns out only in my head...

    I've fixed it, you can now pass the plain session id as a string.
  • Awesome., just re-merged latest in my 1.6 setup and verified.

    I filed one more enhancement for looking for config param instead of specific "Session-Id".., added it into my merged setup.

    Also, somewhat related question.  This enhancement uses the new \Input::headers() function.  I merged that into my override package, where my session driver/db overrides live.  For some reason I cant get the framework to load my override from my package bootstrap.php setup like it does for session files.  Is there anything specific with \Input where it gets loaded before the package bootstraps do?

    EDIT:

    Thought things were working fine.., went back to do some more dev/testing and noticed that it was always failing to return the cookie after pulling it from the header.  Turned out to be the decryption step that returned a null/empty value from the string.  Ended up putting this in:

                if($this->config['encrypt_cookie'] && !$_header_session_id)
                {
                    $cookie = \Crypt::decode($cookie);
                }

    Where $_header_session_id is test var I tossed in and set to true in the block that pulls the id from header
  • I'll think about a configuration item, don't think that is a problem.

    As to Input, that might be used quite early in the boot process, same is true for Config. This means overloading is only possible in the app bootstrap. if you want to know add a Debug::backtrace() to the _init() method of the Input class, so you can see where it's loaded from.

    I will implement your last change. If encryption is a requirement, you should ALWAYS encrypt, no matter if you use a cookie, a POST variable, or the header. So if in your case encryption is enabled, you should put \Crypt::encode($sessionid) in your headers.
  • Will have to think through the encryption part.  Right now we are planning on just only supporting https, an issue with our unique setup is that about 40% of our api routes are implemented in c++/nodejs services, rest with this new fuel setup I am getting going.  Am defaulting to "core api" being fuel side to manage data and sessions, which means when the nodejs side has to check the session_id on its end for validity, checking db and deserializing id doable, but decryption might be too big a pain to get implemented on nodejs end.
    =================================================

    Things seem to be looking pretty good now with the basics.  A new issue I am running into is duplicates/replicating sessions when the REST auth check is happening.  I am currently running simpleauth, and had implemented my own Model_User to run with it (looking to probably move to new ormauth stuff in near future).

    In my rest.auth function check, I have my \Auth::check(); call and it appears that every time that is called when I am testing to make sure an invalid session returns 401/no-access it generates a new session record.

    For example, I truncate the sessions table, then call a REST route with a non-existent session_id 3x.., there will now be 3 session records in the database.  Call it 3x more and there will be 6.., this number seems to continually increase indefinitely during my testing.

    Is there something that could be happening on the perform_check() call that could be causing this dupe side-effect?  Maybe some data missing from loading the session_id from the header where its expecting some other value in the full cookie?
  • The session class creates a new session every time you open one, but no existing one can be found.

    It is not a "dupe" effect, it is creating something that should be there (because you load a session driver, you indicate you need sessions) but isn't. This is by design, and can't be changed.
  • If you don't what that record there, you could do a Session::destroy() if you encounter an "access denied" situation...
  • Thanks for heads up.  I assumed that framework would have only one session record per IP and it would keep using the same session whether auth/un-authed, then when expired would purge at gc time
  • You can't do that. If you open FF, Chrome, Safari and IE from the same computer (for example when you're testing), you'll have 4 valid session records on the same IP.

    There is also no relation between Session (which is meant to create state, to pass data from one request to the next) and Auth (which is an authentication framework with happens to use Session to maintain the login state).

    It is perfectly valid to use sessions to store user data on a site that is completely public, that has no authentication system at all. So the two can not be linked, Auth can (and should) not delete a session merely because the authentication failed. That would remove all other data in the session too.

    I personally never destroy a session. It also stores preferences that should survive a login/logout, and those would be gone after a destroy.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion