Custom fields

By default all user models have the following properties:

  • id (the user unique identifier)
  • created (the user created datetime)
  • updated (the user updated datetime)
  • email (the user email address)
  • verified (indicates whether the user email is verified or not)
  • lastResetSentAt (the last datetime when a password reset email was sent)
  • lastVerificationSentAt (the last datetime when a verification email was sent)

In addition to the above properties, PocketBase allows you to add as many custom fields as you want using the system profiles Collection. The user fields will be appended to each user model under a new profile property.

The easiest way to manage the profiles collection fields is from the cogwheel button in the Users admin page:

Profiles collection screenshot

The only difference between the profiles collection (or any other system collection) and a regular one is that it cannot be deleted or renamed.
This means that you could set custom API rules so that a specific group of users could query and manage the profile data of other users, eg. like in "managers - subordinates" relation (by default only the authenticated profile owner and admins have access to the profile data).
For example, lets say that we have a role text field with "employee" and "manager" as valid values. Based on the field value we can define the following simple rule allowing only an authenticated "manager" user to view/edit other "employee" user profiles:
role = "employee" && @request.user.profile.role = "manager".

To change the profile data programmatically, you could use the Records API and the SDK client in the same way when working with any other Collection Record. Here is an example using the SDKs:

import PocketBase from 'pocketbase'; const client = new PocketBase('http://127.0.0.1:8090'); ... const data = { ... }; const updatedRecord = await client.records.update("profiles", "YOUR_USER_PROFILE_ID", data);
import 'package:pocketbase/pocketbase.dart'; final client = PocketBase('http://127.0.0.1:8090'); ... final data = <String, dynamic>{ ... }; final updatedRecord = await client.records.update("profiles", "YOUR_USER_PROFILE_ID", body: data);

Auth methods

PocketBase provides several ways for users to authenticate:

You could manage the allowed user sign-in/sign-up methods with the Settings API or from the admin UI (Settings > Auth Providers):

Auth providers screenshot

Auth via email

The easiest way to authenticate a user is with its email and password. Here is an example using the JavaScript SDK:

import PocketBase from 'pocketbase'; const client = new PocketBase('http://127.0.0.1:8090'); ... const authData = await client.users.authViaEmail("test@example.com", "123456");
import 'package:pocketbase/pocketbase.dart'; final client = PocketBase('http://127.0.0.1:8090'); ... final authData = await client.users.authViaEmail("test@example.com", "123456");

Auth via OAuth2

Before starting, you'll need to create an OAuth2 app in the provider's dashboard in order to get a client ID and client secret, and register the redirect URL (eg. https://127.0.0.1:8090/redirect.html).
Once you have obtained the client ID and client secret, you can enable and configure the provider from your PocketBase admin settings page.

In general, when authenticating with OAuth2 you'll need 2 client-side endpoints - one to show the "Login with ..." links and another one to handle the provider's redirect in order to exchange the auth code for token.

Web example:

  1. Links page (eg. https://127.0.0.1:8090/ serving pb_public/index.html):

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>OAuth2 links page</title> <script src="https://code.jquery.com/jquery-3.6.0.slim.min.js"></script> </head> <body> <ul id="list"> <li>Loading OAuth2 providers...</li> </ul> <script src="/path/to/dist/pocketbase.umd.js"></script> <script type="text/javascript"> const client = new PocketBase("http://127.0.0.1:8090"); const redirectUrl = "http://127.0.0.1:8090/redirect.html"; async function loadLinks() { const authMethods = await client.users.listAuthMethods(); const listItems = []; for (const provider of authMethods.authProviders) { const $li = $(`<li><a>Login with ${provider.name}</a></li>`); $li.find("a") .attr("href", provider.authUrl + redirectUrl) .data("provider", provider) .click(function () { // store provider's data on click for verification in the redirect page localStorage.setItem("provider", JSON.stringify($(this).data("provider"))); }); listItems.push($li); } $("#list").html(listItems.length ? listItems : "<li>No OAuth2 providers.</li>"); } loadLinks(); </script> </body> </html>
  2. Redirect handler page (eg. https://127.0.0.1:8090/redirect.html serving pb_public/redirect.html):

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>OAuth2 redirect page</title> </head> <body> <pre id="content">Authenticating...</pre> <script src="/path/to/dist/pocketbase.umd.js"></script> <script type="text/javascript"> const client = new PocketBase("http://127.0.0.1:8090"); const redirectUrl = 'http://127.0.0.1:8090/redirect.html'; // parse the query parameters from the redirected url const params = (new URL(window.location)).searchParams; // load the previously stored provider's data const provider = JSON.parse(localStorage.getItem('provider')) // compare the redirect's state param and the stored provider's one if (provider.state !== params.get("state")) { throw "State parameters don't match."; } // authenticate client.users.authViaOAuth2( provider.name, params.get("code"), provider.codeVerifier, redirectUrl ).then((authData) => { document.getElementById("content").innerText = JSON.stringify(authData, null, 2); }).catch((err) => { document.getElementById("content").innerText = "Failed to exchange code.\n" + err; }); </script> </body> </html>