Authentication using Taffy

487 views
Skip to first unread message

Phillip Duba

unread,
Jun 12, 2013, 9:31:22 AM6/12/13
to taffy...@googlegroups.com
Has anyone done authentication/authorization using Taffy? Just wondering if there are any best practices with regards to the framework (and if I missed a Wiki page on it, please feel free to call me out and post the link, :) ),

Phil

Adam Tuttle

unread,
Jun 12, 2013, 1:34:49 PM6/12/13
to taffy...@googlegroups.com
I typically use a two-fold approach:

At login, credentials are sent from the app to the API, over SSL if available, to a white-listed (more on this later) resource like "/auth". If the login is successful, I return a UUID or similar unique identifier with status 200. The same identifier is stored in an active sessions table, with the UUID, the accountId, and the login timestamp, along with any other metadata you might want to capture about the device (platform, version, etc). Failed login I return an error message and status 401.

That UUID is important. It will allow you to revoke access to a specific device without the user having to change their password used on every device, and without having to send the username/password combo with every request. Instead, you include the UUID with every request.

Each request begins in onTaffyRequest (Application.cfc) where we validate the UUID -- unless the request is for "/auth". If the UUID is in the table and doesn't have a soft-delete flag set (call it the ban, block, whatever...) then we allow the request to continue (return true), but if it's been banned, you return an error with status 403. (return representationOf({error:"Your session has been revoked"}).withStatus(403, "Forbidden");)

The app should be able to recognize a 403 in the response to ANY request it makes, and take that as its cue to log the user out. (I usually create an API wrapper layer that takes care of including the UUID in every request and handling 403's, among other things...) Meanwhile you've already change the user's password before revoking the session, so the banned device won't be able to login (unless they know the new password), but the still-approved devices don't have to re-authenticate.

HTH,
Adam


Adam


On Wed, Jun 12, 2013 at 9:31 AM, Phillip Duba <phil...@gmail.com> wrote:
Has anyone done authentication/authorization using Taffy? Just wondering if there are any best practices with regards to the framework (and if I missed a Wiki page on it, please feel free to call me out and post the link, :) ),

Phil

--
You received this message because you are subscribed to the Google Groups "Taffy Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to taffy-users...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Scott Conklin

unread,
Dec 10, 2014, 10:32:54 AM12/10/14
to taffy...@googlegroups.com
I am new to Taffy and really to RESTful APIs in general so i am still trying to wrap my mind around all the concepts.
Particularly,  I am in the middle of trying to sort out an authentication. strategy.

I have read the approach in this thread as well as this blog post  here http://fusiongrokker.com/post/advanced-authentication-with-taffy-apis
but am not sure it quite meets my needs 100%--maybe it does.

I also saw somewhere on this forum that using session variables in a RESful API is an anti-pattern... 
I get that I should be sending the authentication credentials with every request... that I understand, but why would it be a best practices violation to use CF sessions on the backend to maintain the active session? 

What i am looking for is authentication and validation that one would see in a traditional application in that:
1) the user is presented with a login screen
2)  login credentials are entered in a traditional form via form-fields (uname and password)   
3) a CF session is created and checked on every call of the page to ensure it has not expired (or that the user has not explicitly logged out)
4)  in the case  of  x  consecutive minutes of inactivity (or closing of the browser ) the session is destroyed, so whatever action attempted by the user at that time would be intercepted and redirected to the login screen.

This thread  and the blog seem to advocate managing sessions in "active sessions table" which seems to be geared toward one login account being maintained across multiple devices (ipad, phone etc). This implies that  a user logs in only once and is indefinitely  validated or until explicitly revoked from what I can gather.
It seems like extra work of having to check the date of the active session entry in the table if limited sessions are desired .... and I can imagine that there is some extra housekeeping routines necessary to keep the active sessions table cleansed..

My thoughts on an approach where that 

1) send the username and password via a form submit as one would normally do (over SSL) using the white-list approach 
2) authenticate it against whatever security protocol etc
3) set a cf session and the sessionID as  the UUID that is sent on every subsequent request to the API by the authenticated client.
4) on every request, validate the UUID exists AND it is present in the struct of sessions currently active. If not,  then return 403 to which the client must respond by showing a login screen.

Does this sound like a bad approach?  If so, what is a better approach to get authenticated timed sessions while exercising REST best practices? 

Furthermore, I  can't see what role if any HTTP Basic Auth has in all of this.
Seems like HTTP basic Auth is more intended to be used as an APi Key  of sorts rather than for user session management,  correct? seems more  like a facility that validates  that a client is allowed to  to attempt connection to this API irrespective if the api is user/password  protected, correct? 

If not, then  what would be the mechanics by which every request would pass data as an "Authentication Header" for data that must be retrieved from user input? 
(seems awkward.)

Seems like once they enter the data (and it  is "stored" somewhere, local storage?) which is then used to validate  all subsequent API requests that they can interact for as long as they leave the browser open?... I am guessing?   not sure I know what I am asking here..maybe i don't understand what username and password we are talking about when using  HTTP Basic Auth 


Thanks for any help you can offer..

Scott

Adam Tuttle

unread,
Dec 10, 2014, 1:46:42 PM12/10/14
to taffy...@googlegroups.com
My responses are inline, in blue, below. Hope this helps.

Adam

On Wed, Dec 10, 2014 at 10:32 AM, Scott Conklin <scon...@dynaprice.net> wrote:
I am new to Taffy and really to RESTful APIs in general so i am still trying to wrap my mind around all the concepts.
Particularly,  I am in the middle of trying to sort out an authentication. strategy.

I have read the approach in this thread as well as this blog post  here http://fusiongrokker.com/post/advanced-authentication-with-taffy-apis
but am not sure it quite meets my needs 100%--maybe it does.

I also saw somewhere on this forum that using session variables in a RESful API is an anti-pattern... 
I get that I should be sending the authentication credentials with every request... that I understand, but why would it be a best practices violation to use CF sessions on the backend to maintain the active session? 

Because REST is stateless. By maintaining a session, you're maintaining state. Sure, you could set session.isLoggedIn=true, but in order to maintain that session, the client has to send the cfid+cftoken/jsessionid cookies with every request. Cookies are another REST anti-pattern. And it doesn't get you anything: The client still has to remember *something* and include it in every request.

Just don't do it! :o)
 
What i am looking for is authentication and validation that one would see in a traditional application in that:
1) the user is presented with a login screen
2)  login credentials are entered in a traditional form via form-fields (uname and password)   
3) a CF session is created and checked on every call of the page to ensure it has not expired (or that the user has not explicitly logged out)
4)  in the case  of  x  consecutive minutes of inactivity (or closing of the browser ) the session is destroyed, so whatever action attempted by the user at that time would be intercepted and redirected to the login screen.

What you are describing here is not an API, but an application. While there are mechanisms to indicate that login is required, to which a *browser* will prompt the user for a username and password, forms/"screens" are NOT REST. You can't return a login form. This isn't an HTML application. It's strictly data going back and forth.

This is not to say you can't allow and require authentication. The blog post you linked discusses exactly that. All authentication is done through a dedicated authentication resource, which saves information about the client and returns that client's api key (if login was successful). That's as close as you can realistically get to a "login screen."

The way to make *browsers* require authentication is to support HTTP Basic Auth, and to return an appropriate WWW-Authenticate header when (additional) login is required. When you're browsing the web and all of a sudden get prompted for a username and password by your browser (not in a web page), that's HTTP Basic Auth in action. But remember: APIs are not generally something browsed by typing in the URL bar. They are for other programs to consume... So it doesn't matter what type of auth mechanism you use as long as clients can make use of it to get stuff done.

This thread  and the blog seem to advocate managing sessions in "active sessions table" which seems to be geared toward one login account being maintained across multiple devices (ipad, phone etc). This implies that  a user logs in only once and is indefinitely  validated or until explicitly revoked from what I can gather.
It seems like extra work of having to check the date of the active session entry in the table if limited sessions are desired .... and I can imagine that there is some extra housekeeping routines necessary to keep the active sessions table cleansed..

My thoughts on an approach where that 

1) send the username and password via a form submit as one would normally do (over SSL) using the white-list approach 
2) authenticate it against whatever security protocol etc
3) set a cf session and the sessionID as  the UUID that is sent on every subsequent request to the API by the authenticated client.
4) on every request, validate the UUID exists AND it is present in the struct of sessions currently active. If not,  then return 403 to which the client must respond by showing a login screen.

Does this sound like a bad approach?  If so, what is a better approach to get authenticated timed sessions while exercising REST best practices? 

Your understanding of the recommendation is not far off. I suppose you could think of it as an "active sessions table" but not in the same way that CF sessions work. They should never automatically expire due to inactivity. It is feasible (though annoying) that for security reasons your keys only last a set duration (e.g. 1 month) from when they are issued, and then must be replaced.

But think of the keys as a personal combination for a locked door with a number-pad on it, where you enter your code to open the door. The building owner assigns everyone a unique code that can be logged to know who is accessing what doors, and when; and the building manager can deactivate the code at any time to disallow you any further access. (In this metaphor, you would be instantly transported outside of the locked room and anything you hadn't already taken out with you would still be locked inside -- and now your code doesn't work any more).

I've already discussed why sessions + the cookies required to make them work are a bad idea, so I won't repeat that here.
 
Furthermore, I  can't see what role if any HTTP Basic Auth has in all of this.
Seems like HTTP basic Auth is more intended to be used as an APi Key  of sorts rather than for user session management,  correct? seems more  like a facility that validates  that a client is allowed to  to attempt connection to this API irrespective if the api is user/password  protected, correct? 

If not, then  what would be the mechanics by which every request would pass data as an "Authentication Header" for data that must be retrieved from user input? 
(seems awkward.)

Seems like once they enter the data (and it  is "stored" somewhere, local storage?) which is then used to validate  all subsequent API requests that they can interact for as long as they leave the browser open?... I am guessing?   not sure I know what I am asking here..maybe i don't understand what username and password we are talking about when using  HTTP Basic Auth 

There are a couple of use cases that make Basic Auth a reasonable thing to use:

1. You the developer just use your account for all access. Maybe you're tracking comment data on movies over time from something like an IMDB API. So you hard-code in your username and password into the requests. It's never going to change unless you change your password.

2. Consider a mobile app. If you were to issue an api key to each user out-of-band from the mobile app, the user would have to find a way to copy and paste it into the mobile app somewhere -- that would be horrible and clunky. Instead, the app can just ask for their username and password, save them locally inside the app's storage, and then include them with all requests as appropriate.

In the case of #2, the app can do the same thing, but use the username and password to authenticate with an api as described in the blog post you linked, and then save the API key and send that, instead of the username and password, with subsequent requests.
 
Thanks for any help you can offer..

Scott


Always happy to help.
 

On Wednesday, June 12, 2013 12:34:49 PM UTC-5, Adam Tuttle wrote:
I typically use a two-fold approach:

At login, credentials are sent from the app to the API, over SSL if available, to a white-listed (more on this later) resource like "/auth". If the login is successful, I return a UUID or similar unique identifier with status 200. The same identifier is stored in an active sessions table, with the UUID, the accountId, and the login timestamp, along with any other metadata you might want to capture about the device (platform, version, etc). Failed login I return an error message and status 401.

That UUID is important. It will allow you to revoke access to a specific device without the user having to change their password used on every device, and without having to send the username/password combo with every request. Instead, you include the UUID with every request.

Each request begins in onTaffyRequest (Application.cfc) where we validate the UUID -- unless the request is for "/auth". If the UUID is in the table and doesn't have a soft-delete flag set (call it the ban, block, whatever...) then we allow the request to continue (return true), but if it's been banned, you return an error with status 403. (return representationOf({error:"Your session has been revoked"}).withStatus(403, "Forbidden");)

The app should be able to recognize a 403 in the response to ANY request it makes, and take that as its cue to log the user out. (I usually create an API wrapper layer that takes care of including the UUID in every request and handling 403's, among other things...) Meanwhile you've already change the user's password before revoking the session, so the banned device won't be able to login (unless they know the new password), but the still-approved devices don't have to re-authenticate.

HTH,
Adam


Adam


On Wed, Jun 12, 2013 at 9:31 AM, Phillip Duba <phil...@gmail.com> wrote:
Has anyone done authentication/authorization using Taffy? Just wondering if there are any best practices with regards to the framework (and if I missed a Wiki page on it, please feel free to call me out and post the link, :) ),

Phil

--
You received this message because you are subscribed to the Google Groups "Taffy Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to taffy-users...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

--
You received this message because you are subscribed to the Google Groups "Taffy Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to taffy-users...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Scott Conklin

unread,
Dec 10, 2014, 3:44:12 PM12/10/14
to taffy...@googlegroups.com
Adam-

Thanks so much for such  a quick and detailed response... 
A couple of comments/questions:

1) I understand that forcing the client to use sessions and cookies for each request is bad..I don't think i was saying that... at least I did not intend to do so.
What I wanted to say is that I want to follow the recommendations pretty much exactly as prescribed in the article  http://fusiongrokker.com/post/advanced-authentication-with-taffy-apis with the following exception:

instead of doing this:
//create a new device token:
        var deviceToken = createUUID();

        //saving the device token to the database is up to you...
        saveDeviceToken(username, deviceId, deviceToken);
I am proposing to use the Railo sessionID as the UUID and skip saving anything in the db. Passing back the sessionID as UUID will then act as the devicetoken for subsequent requests in your example code.  The validateToken function implementation details would then check that the DeviceToken is a valid key in the session struct.. If not found for whatever reason-- (disappeared  because of a timeout which is important for me)  or does not exist, then a 403 response is returned . Everything else follows your recommendation.  The client and the API is really not session/cookie aware and the details of how the deviceToken are created/validated are encapsulated on the backend.
Would you still recommend against this? (I suppose i could use a db table and do it exactly as you are but then would need to check create timestamps on each request and revoke/remove tokens accordingly myself.


2) >> What you are describing here is not an API, but an application. While there are mechanisms to indicate that login is required, to which a *browser* will prompt the user for a username and password, forms/"screens" are NOT REST. You can't return a login form

I realize that.. I was merely describing the requirements of the application which is to be a single page app built in ReactJS . There is the need to log a user in to gain access to certain content(screens). The only role of the server side is to marshal data from the db (as JSON) to the datastore (Flux) using Ajax.I thought to accomplish this that a Restful API would be appropriate. It is basically a CRUD app. Are you saying that this would not be a good fit for a RESTful API?  
I am not trying to do anything with returning forms etc.. but merely statuscodes and/or data when login is required which should NOT be a one time occurrence, but something that can expire.

3) >> They should never automatically expire due to inactivity. It is feasible (though annoying) that for security reasons your keys only last a set duration (e.g. 1 month) 

They must and a month is way too long.. What i am describing is not unlike a session one experiences when they go to their banking software.. If you walk away for even an hour, chances are you are either logged off automatically OR when you try to click anywhere you are redirected to the login page with an explanation about inactivity. 
I am not talking about the screen /forms,message or the  redirect etc.. I am talking about driving the session "length"  as part of expired CF Session in the back-end validation check  which is being tested against the "deviceToken" , "UUID key" or whatever we call it sent in by the API on every single request. 
I really don't care about authenticating  "a device".


4)  >> But think of the keys as a personal combination for a locked door with a number-pad on it, ... 
following your metaphor example... yes, but i need to 
a)  issue a personal combination that is only good for a fixed period of time which is different each time it is issued.
b) you get a new combination when you provide the username and password (on a login form) which does not change (passwords stored in a db and are one-way encrypted)
 
5) I understand what you are saying about Basic Auth, I think you are confirming what i was thinking and it is not necessary  in what i propose much in the way that your advanced technique article makes no use of it. 

Thanks again for any advice
Scott

Adam Tuttle

unread,
Dec 22, 2014, 9:46:29 AM12/22/14
to taffy...@googlegroups.com
Responding inline again... Hope all of this helps.

Adam

On Wed, Dec 10, 2014 at 3:44 PM, Scott Conklin <scon...@dynaprice.net> wrote:
Adam-

Thanks so much for such  a quick and detailed response... 
A couple of comments/questions:

1) I understand that forcing the client to use sessions and cookies for each request is bad..I don't think i was saying that... at least I did not intend to do so.
What I wanted to say is that I want to follow the recommendations pretty much exactly as prescribed in the article  http://fusiongrokker.com/post/advanced-authentication-with-taffy-apis with the following exception:

instead of doing this:
//create a new device token:
        var deviceToken = createUUID();

        //saving the device token to the database is up to you...
        saveDeviceToken(username, deviceId, deviceToken);
I am proposing to use the Railo sessionID as the UUID and skip saving anything in the db. Passing back the sessionID as UUID will then act as the devicetoken for subsequent requests in your example code.  The validateToken function implementation details would then check that the DeviceToken is a valid key in the session struct.. If not found for whatever reason-- (disappeared  because of a timeout which is important for me)  or does not exist, then a 403 response is returned . Everything else follows your recommendation.  The client and the API is really not session/cookie aware and the details of how the deviceToken are created/validated are encapsulated on the backend.
Would you still recommend against this? (I suppose i could use a db table and do it exactly as you are but then would need to check create timestamps on each request and revoke/remove tokens accordingly myself.

It's been a few years since I focused on the particulars of this, but I think you either need to include the (e.g. CFID & CFToken) cookise in the request or pass the url parameters of the same name, in order to connect the request to the existing session. The app server will not look for or find it in a request-body scenario, like a POST or PUT. You might be able to have them put their CFID & CFToken in the URL _and_ make a PUT/POST request with a normal body... but I won't go out of my way to support this behavior if it doesn't work.

It sounds to me like you're trying to avoid doing some work, and in doing so, proposing things that violate some of the core concepts of REST. It would be almost trivial to just create a query object, throw it in application scope, and insert rows into that table with the UUID you create for a new user -- nobody says you have to persist api keys to the database. And you can timestamp those records and update/delete/expire them as you see fit.

I hate to be the guy that says, "That's not RESTful!" because at the end of the day, if it works and you can get your job done, great... But just know that what you're proposing is going to be foreign to anyone that has worked with traditional APIs and they may question your competence with REST because of it.

 
2) >> What you are describing here is not an API, but an application. While there are mechanisms to indicate that login is required, to which a *browser* will prompt the user for a username and password, forms/"screens" are NOT REST. You can't return a login form

I realize that.. I was merely describing the requirements of the application which is to be a single page app built in ReactJS . There is the need to log a user in to gain access to certain content(screens). The only role of the server side is to marshal data from the db (as JSON) to the datastore (Flux) using Ajax.I thought to accomplish this that a Restful API would be appropriate. It is basically a CRUD app. Are you saying that this would not be a good fit for a RESTful API?  
I am not trying to do anything with returning forms etc.. but merely statuscodes and/or data when login is required which should NOT be a one time occurrence, but something that can expire.

If your application is the only one that will be consuming the API, you may be able to lax security a little bit. Instead of using a session, create a temporary api key and throw it into application or server scope as appropriate. The API will validate requests against the key to authenticate the requests, and the app can just embed the key in its memory (in a JS variable on the page) to use for requests. If you rotate the key frequently enough, this could be enough security. (Also disable CORS)
 
3) >> They should never automatically expire due to inactivity. It is feasible (though annoying) that for security reasons your keys only last a set duration (e.g. 1 month) 

They must and a month is way too long.. What i am describing is not unlike a session one experiences when they go to their banking software.. If you walk away for even an hour, chances are you are either logged off automatically OR when you try to click anywhere you are redirected to the login page with an explanation about inactivity. 
I am not talking about the screen /forms,message or the  redirect etc.. I am talking about driving the session "length"  as part of expired CF Session in the back-end validation check  which is being tested against the "deviceToken" , "UUID key" or whatever we call it sent in by the API on every single request. 
I really don't care about authenticating  "a device".

This information you gave about the API backing an app with sessions does add a lot of relevant context, and does change things slightly. I still think requiring session information is going to be the wrong approach, though.

I would just do in-memory API keys stored in your API's application scope, and they time out like 2 minutes after your app would otherwise time itself out. Just create a query variable and keep it in memory... But still do API key generation as described in the article.
Reply all
Reply to author
Forward
0 new messages