Skip to content

User Management

This section details how user accounts can be created and managed.

Each user account is required to be assigned an email address as well as a username. The email address is needed for authentication and sending API notifications while the username is used by applications and API internals to manage data ownership. This makes it possible for users to change their email address without affecting existing data and apps configuration.

Note

As a convenience, email addresses may be stored in the TOML settings file to then login with the username on the command line.

Each user account needs to be verified to gain full access of the available features. This should be done via email verification with a unique link. If SMTP is not configured for the API instance, it can be done via the renelick-admin command line utility invoked from within the API service container to directly update the database entry.

When a user account needs to be closed, rather than deleting it which would in principle require all its related data to be deleted too, a standard practice is to deactivate the account instead. This can be done with the renelick-admin tool in a similar way, to unset the is_active flag.

Some users can be granted additional permissions and become "superusers". This is for example required to perform some maintenance tasks such as updating accounts and data that belongs to another user. There should typically be at least one superuser created when the API instance is initially deployed.

Standard Authentication

To register a new user, an email address and username need to be provided:

$ renelick user register EMAIL USERNAME

On private instances, registering new users typically requires a superuser or "admin" to run this command. That's when the ADMIN_REGISTER environment variable is set to true in the API service, which is the default. To disable it, add ADMIN_REGISTER=false to the .env file and restart the API service. This is needed initially to create the first superuser. Then to register a new regular user with the flag enabled again, first login with the superuser account and then pass its name to the --admin argument:

$ renelick user register --admin=ADMIN EMAIL USERNAME

For example, to register a user bob and if the superuser is admin:

$ renelick user register --admin=admin bob@example.com bob

Login

Once a user has been registered, it's time to login:

$ renelick login bob

This command creates a JWT token which will be valid for an hour. Once expired, you will need to login again (until refresh tokens are supported by the API).

To check whether you're currently logged in:

$ renelick whoami
JWT expires in 59 minutes.
Connecting to http://172.17.0.1:8000
User profile:
  id             67881592413337823cc732c3
  username       bob
  email          bob@example.com
  full_name
  is_superuser   False
  is_verified    False

Verification

This is when users would need to be verified, to confirm their email address is correct and avoid fake user accounts. Now we know the unique id for the user that was just created, we can run this command:

$ uid=67881592413337823cc732c3
$ docker-compose exec api renelick-admin $uid set verified

Going Further

If you also wanted to give superuser permissions to a user account:

$ docker-compose exec api renelick-admin $uid set superuser

Note

See also the Quick-Start Guide about how to set up a new instance from scratch.

In some cases, the credentials have to last longer than an hour. For example, thiw would be the case with services that aren't run interactively but need to be always connected to the API. It's possible to get a persistent API key when logging in instead of a temporary JWT as shown below:

$ renelick login --method=key bob

Finally, to avoid having to pass the username on the command line all the time, a default one may be found in settings.toml either explicitly in the [default] section or by looking up the first user listed for the matching API instance. The settings.toml file will be updated automatically when registering new users or when logging in.

OAuth2 Authentication

It's also possible to login using third-party credential providers via OAuth2. Support has been implemented at the API level for Google authentication but not in the reference web frontend or command line tools yet. So it can be used but currently requires some manual steps. If there is already an existing Renelick user account with the same email address as the Google account then it will be reused by storing some Google information in the Renelick database.

Google OAuth2 Configuration

Note

Google authentication requires going through a verification procedure for a full production deployment, otherwise the number of users is limited to 100. This is not detailed here.

The first step is to enable the People API in GCP. To do this, you'll need to create a Google Cloud account if you don't already have one. Then visit the People API page and enable it.

Next, an OAuth2 client entry needs to be set up in GCP for your API instance. This can be done on the clients page by providing the following values:

  • Application Type: Web application
  • Name: Arbitrary Renelick deployment name
  • Authorized redirect URIs: https://renelick-url/v0.14/auth/google/callback

Adjust the redirect URI with your own deployment domain name, port number etc. To try OAuth2 with a local deployment, provide this default URI: http://127.0.0.1:8000/v0.14/auth/google/callback

Note

The Renelick API version v0.14 is hard-coded in this example. Using latest should work too but is not fully tested yet.

Once the OAuth2 client has been created, an ID and secret will be provided. Add them to your API deployment's .env file as follows:

GOOGLE_CLIENT_ID=<your client id>
GOOGLE_CLIENT_SECRET=<your client secret>

It's also necessary to generate a random OAuth2 local secret which will be used when generating the tokens:

$ echo "OAUTH2_SECRET=$(pwgen -y -n1 32)" >> .env

Make sure the API service is restarted in order to load these new environment variables. You should see this message in the API log:

renelick-api    | INFO:     Google OAuth2 authentication enabled

Then go to the scopes page and add the following items:

  • ./auth/userinfo.email
  • ./auth/userinfo.profile
  • openid

This will make it possible for Google user accounts to share their email address and profile data with the Renelick API to store it alongside their local user accounts. In particular, the email address is used to link any existing Renelick user account with a matching Google one.

Manual Login

Frontend Integration

This is where the web frontend integration is currently missing, to provide an option to login with a Google account on the login page and then store the JWT in the session to access the Renelick API via the web frontend directly in the browser. Some follow-up improvements could also be done to facilitate this with CLI tools.

The first step is to get a Google login URL via the authorize endpoint. In the example below, we're using the default docker-compose local deployment but this should work with any public one too:

$ curl http://127.17.0.1:8000/latest/auth/google/authorize
{"authorization_url":"https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=<CLIENT-ID>&redirect_uri=http%3A%2F%2F127.17.0.1%3A8000%2Fv0.14%2Fauth%2Fgoogle%2Fcallback&state=<STATE>&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email"}

The CLIENT-ID and STATE values have been removed from the example above, but they should be long random strings. The CLIENT-ID value should match the client ID stored earlier in the .env file. Note that the callback URL here does contain the exact Renelick API version v0.14 which is why it was explicitly mentioned in the setup instructions. This may be adjusted to use latest instead.

The next step is to open this unique URL as-is in a web browser and follow the instructions. Once logged in with the Google account, the browser will send a request to the callback URL with a JWT token and the user account information. If this is all done correctly, the Renelick API will accept the request and store the OAuth2 credential within any exisinting user account with a matching email address. It will then return the JWT which will appear as raw JSON in the browser window:

{"access_token":"<JWT>","token_type":"bearer"}

The actual JWT value can then be stored manually in the ~/.config/renelick/credentials.json file and used to access the API.

To check whether it's working as expected, here with a gtucker user:

$ renelick whoami
JWT expires in 54 minutes.
Connecting to http://172.17.0.1:8000
User profile:
  id             678788e8d5a0ff2512f495cd
  username       gtucker
  email          gtucker@gtucker.io
  full_name
  is_superuser   False
  is_verified    False

The Renelick user entry in the database should now also contain the OAuth2 account details since they both have the same email address:

$ docker-compose exec mongo mongosh renelick
[...]
renelick> db.user.findOne({username: 'gtucker'})
{
  _id: ObjectId('678788e8d5a0ff2512f495cd'),
  username: 'gtucker',
  full_name: null,
  email: 'gtucker@gtucker.io',
  hashed_password: '<HASHED_PASSWORD>',
  is_active: true,
  is_superuser: false,
  is_verified: false,
  oauth_accounts: [
    {
      id: ObjectId('678814ae413337823cc732c2'),
      oauth_name: 'google',
      access_token: '<JWT>',
      account_id: 'people/<ACCOUNT-ID>',
      account_email: 'gtucker@gtucker.io',
      expires_at: 1737020542,
      refresh_token: null
    }
  ]
}

with the sensitive bits removed i.e. HASHED_PASSWORD, JWT and ACCOUNT-ID.

Note

A refresh token may also be issued to stay logged in longer than the JWT expiry period. This feature isn't currently supported.