I am working on a hobby project which will involve a web server (hosted and owned by me) and a native app (which will communicate with the web server periodically) an end-user can install via a deb/rpm package. This native app has no traditional UI (besides via command line) and can be installed on browser-less environments. Additionally, I’m trying to avoid registering custom URL schemes. As such, I do not wish to use redirect flows, if possible.
The web server and the native app will both be open source and the code will be visible to everyone, but I suppose it shouldn’t matter in the context of authentication. However, I wanted to point that out in case it matters.
So far, during my research, I’ve come across two mechanisms which seem suitable for what I am trying to achieve:
- Resource Owner Password Credentials Grant
- Device Authorization Grant
Unfortunately, I’ve come across a lot of articles and blogs stating that Resource Owner Password Credentials Grant should no longer be used. Not sure how much weight I should give these articles, but I’m leaning towards Device Authorization Grant for now.
From my understanding, one of the steps involved in this grant is the client will continuously poll the server to check if the user has authenticated the client. However, instead of polling the server, why not flip the place where the code is entered?
In other words, instead of the client/device displaying a code to the user and the user then entering the code on the server, why not display the code on the server and have the user enter the code into the client? This way the client doesn’t have to needlessly poll the server? Does this not achieve the same thing? I’m really not sure though. I want to ensure I’m not missing something before I implement this.
This is how I envision the general flow for users using my project:
- The user would register an account on my site (i.e, the web server). This is just a traditional username and password authentication.
- The user can then download and install the deb/rpm package which contains my native app. Although, it should be noted that there’s obviously nothing preventing the user from installing the package without registering an account on the server. The whole point of this authentication is create a link between the account on the server and the native app.
- Prior to enabling the daemon/service functionality of the native app, the user will need to authenticate the native app to the server.
- To do so, the user can log into the server (using their regular username/password creds) and generate a temporary token.
- The user can then use the CLI functionality of the native app to use this temporary token. For example, the user may type
my_app_executable authenticate, where
my_app_executableis the binary executable and
authenticateis the parameter.
- This will prompt the user to enter their username and the temporary token.
- The app will then send the entered username and temp token to the server which will validate this combination. If it’s valid, the server will send a access token back to the app.
- The app can then use this access token to communicate with the server. Authentication complete.
Based on this, I have a couple of questions:
- Does this flow seem secure? Is there an aspect of this that I’m overlooking?
- Is it okay to more or less permanently encrypt and persist this access token on the filesystem? If the user turns off the native app for months and then they turn it back on, I would like it to function normally without making the user authenticate again. I suppose I’ll need to implement a way to revoke an access token, and I’m thinking about tracking this in the database on the server side. This would mean that for each HTTP request from the app to the server, the server will need to make a DB check to ensure the access token hasn’t been revoked.