A flexible oAuth 2.0 consumer service should allow programmers to store data about clients requesting authentication. This allows programmers using the authentication service to do things like serving clients at multiple domains, which would require storing a callback URL for each oAuth request. Typically, this would mean storing client state on the oAuth consumer server in a session object native to a server-side scripting language (i.e. in Python, PHP or Ruby), or in a database like MySQL or MongoDB, or even just in a file somewhere on the server. Client data is usually indexed by a unique ID that is stored in a cookie or passed as a local state parameter through the oAuth flow.
Server storage is a solution for tracking client state, but it is not an elegant one. Why write and maintain a web service if you can store state client side in a browser cookie? This is easier, but the problem with this approach is that your program is not guaranteed to have access to cookies in every browser. For example, an end user might have cookie permissions turned-off by default.
This is where stateless oAuth comes in to the picture. Stateless oAuth flow allows us the ease of client-side data storage for client specific information without relying on the availability of browser cookies. The local state parameter in oAuth 2.0 is designed for precisely this use case, but unfortunately it is not supported by the most popular oAuth providers today, including Facebook.
But if we are passing a redirect URL in the oAuth specification anyway, then why not just encode client state in a URL parameter if it is small enough to fit? This solution works well except for the fact that many special characters are disallowed in the redirect_uri parameter specification, most notably percent “%” and slash “/”. This limitation makes it very hard to put a nested callback URL as a query string parameter of the redirect URL. The most often cited solution here is to base64 encode client state using a file system encoding scheme to avoid getting another slash “/”, and then append it as a query string parameter to the redirect URL. When the client gets redirected back to the authentication service from the oAuth provider site, we can decode the client state from the query string.
Unfortunately there is another problem with this solution. When a string is base64 encoded, often times equal signs “=” are appended as padding characters to normalize the length of the encoded strings, and the equal sign is also an illegal character in the redirect_uri parameter. There are a few ways around this. You can replace these equal signs with a valid redirect_uri character, like perhaps an underscore “_”. Alternatively you can strip away the equal signs before starting the oAuth flow and then add them back once the client returns from the oAuth provider site. Since the amount of padding characters needed is determined solely by the length of the encoded string, adding the characters back is trivial, and might look something like this:
cb_url += "=" * ((4 - len(cb_url) % 4) % 4)
cb_url = base64.b64decode(cb_url)
Until mainstream oAuth providers support local state, base64 encoding local state into a redirect URL parameter is the best way to avoid storing client state on the server. With only a few lines of client-side code, stateless oAuth is an elegant way to store client data without relying on cookie access or writing and maintaining an extra server-side service.