Search

What the Quote?

"Or, maybe he's just as passionate about whatever it is he's talking about as I am about robot nausea."

Tim Tripcony

"You just said, 'I please myself, donkey'."

Laura Tripcony

"It won't scan the monkey!"

Tim Tripcony

« Rolling your own authentication for REST API's, part 6 - the sum of the parts | Main| characteristics of an App Store »

Rolling your own authentication for REST API's - Epilogue

Category xpages

In summary, let's recap some of the most unconventional characteristics of this approach to authentication:


  • We're storing a hashed representation of the user's password directly within the application, but do not store their user ID within the same record.

  • Despite not storing the user ID in the record that stores their password, we can rapidly retrieve the password when we need to because the UNID for that record adheres to a format that is both predictable and inexpensive to calculate.

  • Once the user has been registered, their password never needs to be sent to our application again. As long as the consumer knows the user's ID and password, it can generate a temporary API key based on tokens it requests from the API.

  • Our token and key format causes tokens to expire after a period of time of our choosing, allowing each consumer to cache tokens temporarily but not indefinitely. This allows users to perform multiple operations during a single session without having to request a new token for each. This approach minimizes both the total traffic to our application and the response time for each operation, but also minimizes the period of time during which an intercepted key can be used maliciously.

  • We never store either the token that we send to the consumer or the API key we expect to receive in return, but because we know what that key must be, we assign the token record a predictable UNID, allowing both the validity and the identity of the user to be rapidly calculated.

  • The use of a predictable UNID for both account records and token records removes the need to create views that display either document type. This reduction of the indexing burden that the application places on the Domino server, in addition to the rapid retrieval of data when requested, provides superior scalability and performance compared to traditional Domino data structures.

  • Most importantly, by preventing all users – both anonymous and conventionally authenticated – from accessing any data or design elements other than the XPage design elements used to surface our API to consumer applications, we are able to keep our application's data entirely secure despite being unable to leverage the entire security model that is built into the Domino application model.


I hope that you've found this article informative, and that this approach to authentication gives you yet another way to use Domino to provide amazing application experiences to your users.


FIN

Download this entire article as:

For additional convenience, here are links to each section of this article:

  1. Putting your data to REST
  2. Making a Token gesture
  3. Anonymity is a warm blanket
  4. Welcome to the club
  5. The Keymaster and the Gatekeeper
  6. The sum of the parts

Comments

Gravatar Image1 - Great series Tim. Thanks for taking the time to put this in a blog series. I am not quite sure if/when I would need to use this but I learnt a lot from the general techniques you were applying to solve the overall need. I am guessing the way we are going with mobile devices, SaaS etc. this will soon become an important technique to have in our developer kit. At some time I would like to encapsulate what you have done as a new set of methods for my own ·dominoFramework.

Gravatar Image2 - Karsten, Squawk { Link } originally used no views at all. Eventually we decided that the "Community Squawks" transcript might as well be a view, because it's just all squawks listed in descending order, so it seemed silly not to just use a view. But every other query - "My Flock's Squawks", "My Replies", etc. - uses a variation on the digest search technique (the article you linked to was our original inspiration for some of our design techniques in Squawk). That's the reason that, without even bothering to use scope caching, it's so much faster than it would be if we were using views to do our indexing for us.

In that application, we don't have to worry (as much) about replication conflicts because not only does the nature of the application dictate that, once a document is created, it's never modified again, but the digest is also designed to be user-based: when you post a squawk, you're updating a digest that is specific to you, so no user ever modifies the same document as another user. It's possible, of course, that the same user could get routed to multiple servers for separate transactions that each result in a digest modification, but that's most likely to occur in a cluster, which means that replication should be occurring almost immediately instead of on a schedule. Obviously, though, offline usage would present other challenges.

Although we didn't go this route with Squawk, another approach would be to maintain some or all of the digest data in memory: for example, when a user submits data, after writing it back to the NSF, also make an update to some SortedMap in an applicationScope'd managed bean that also does lazy loading so that, if the data being queried isn't already stored in scope (or has been purged due to a reboot or design modification), it does a fresh pull from the actual documents. You'd have to be careful with this approach for several reasons: you'd want to limit how much data you store about each record in memory, or the server would eventually (if not rapidly) explode; you can only store metadata about each document, not actual document handles, since Domino will recycle those handles after each request; finally, if the data model also includes Reader fields or other security restrictions, storing too much in scope would allow users to see data they shouldn't, even if they're unable to access the full document that data represents.

But it's definitely possible, though I'm not sure I'd recommend designing every application this way - just applications that would benefit from extremely rapid response times and are already conceptually structured in a way that fits this model well. But it's an extremely powerful way to approach maximizing performance... we just have to be willing to be "programmers", not just "developers". Emoticon

Speaking of which, Nathan's already publicly thanked you for this, but I also wanted to thank you for the articles you posted last year about managed beans. That information has been absolutely essential to how we've designed our applications ever since.

Gravatar Image3 - Thanks for the article. The digest search (also described here: { Link } ) is a very interesting approach to speed up lookup operations.
What do you think - is it possible to create a whole application based on digest search without using ANY views and in addition support replicated environments (be able to handle replication conflicts)?
For that scenario, you would have to create all document lists on your own, e.g. with special documents that represent the list position of a document and pointers to the previous and next entry to use it like views.
I'm curious if that would increase or decrease performance, because you would loose the benefit of a stored view index. Writing data takes longer because you need to update all document lists on your own (which could be done in a background thread). The question is whether reading data via digest is so much faster compared to using Notes views and how to detect changes coming in via replication in order to update the index. Looks like it would also mean to create an index for each server and not to replicate it between replicas.
Interesting thought.

Gravatar Image4 - "What do you think - is it possible to create a whole application based on digest search without using ANY views and in addition support replicated environments (be able to handle replication conflicts)?"

Yes it is. And Tim and I have done it before. It's probably easier than you think, since the whole "replication conflict" story is based on the assumption of updating existing documents, when you don't really have to. Keeping transactional audit trails makes that a lot easier.

Post A Comment

:-D:-o:-p:-x:-(:-):-\:angry::cool::cry::emb::grin::huh::laugh::lips::rolleyes:;-)