Skip to content

External OAuth Authentication

NpgsqlRest supports OAuth authentication with popular external providers including Google, LinkedIn, GitHub, Microsoft, and Facebook.

Overview

json
{
  "Auth": {
    "External": {
      "Enabled": true,
      "SigninUrl": "/signin-{0}",
      "ReturnToPath": "/",
      "LoginCommand": "select * from external_login($1,$2,$3,$4,$5)"
    }
  }
}

Settings Reference

SettingTypeDefaultDescription
EnabledboolfalseEnable external OAuth providers.
BrowserSessionStatusKeystring"__external_status"sessionStorage key for auth status (HTTP status code).
BrowserSessionMessageKeystring"__external_message"sessionStorage key for auth message.
SigninUrlstring"/signin-{0}"Sign-in page URL pattern. {0} is replaced with provider name.
SignInHtmlTemplatestring(see below)HTML template for the sign-in page.
RedirectUrlstringnullURL to redirect after auth. Usually auto-detected.
ReturnToPathstring"/"Default path to redirect after auth completes.
ReturnToPathQueryStringKeystring"return_to"Query string key for dynamic return path.
LoginCommandstring"select * from external_login($1,$2,$3,$4,$5)"PostgreSQL command to execute after OAuth login. Uses the same result processing logic as the login endpoint.
ClientAnalyticsDatastring(JavaScript object)Browser analytics data sent to login command.
ClientAnalyticsIpKeystring"ip"JSON key for client IP in analytics data.

SignInHtmlTemplate

HTML template for the sign-in page shown during communication with the OAuth provider. This is typically a simple loading page. You can customize this to show your own loading animation, spinner, or branding. Format placeholders:

  • {0} - Provider name (e.g., "Google", "GitHub")
  • {1} - JavaScript to redirect to the external auth provider

Default value:

html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Talking To {0}</title>
</head>
<body>
  Loading...
  {1}
</body>
</html>

Login Command

The LoginCommand is a PostgreSQL command that executes after successful OAuth authentication. It uses the same result set conventions as the login annotation - column names, special columns (status, scheme, body), and claim handling all work identically.

For full details on how the result set is processed (return type requirements, special columns, claim types, status codes), see the Login Endpoint Conventions documentation.

Parameters

The LoginCommand receives up to five parameters:

ParameterTypeDescription
$1textExternal login provider name (e.g., "google", "github")
$2textUser's email address
$3textUser's display name
$4text/json/jsonbRaw JSON data from the OAuth provider
$5text/json/jsonbBrowser analytics data (screen size, timezone, etc.)

Result Set Conventions

The command must return a named record (table). The result is processed using the same rules as login endpoints:

  • Special columns: status, scheme, body control login behavior (see Special Columns)
  • All other columns: Become security claims (column name = claim type, column value = claim value)
  • Empty result: Returns 401 Unauthorized
  • Multiple rows: Only the first row is processed

Example Login Command Function

sql
create function external_login(
    _provider text,
    _email text,
    _name text,
    _data jsonb,
    _analytics jsonb
)
returns table(status boolean, id int, name text, email text, provider text)
language plpgsql as $$
declare
    _user_id int;
begin
    -- Find or create user
    select id into _user_id from users where email = _email;

    if _user_id is null then
        insert into users (email, name, created_via)
        values (_email, _name, _provider)
        returning id into _user_id;
    end if;

    -- Return claims (same format as login endpoint)
    return query
    select
        true as status,
        _user_id as id,
        _name as name,
        _email as email,
        _provider as provider;
end;
$$;

OAuth Providers

NpgsqlRest includes pre-configured defaults for Google, LinkedIn, GitHub, Microsoft, and Facebook. For these providers, you only need to set ClientId and ClientSecret - all URL settings have sensible defaults.

Minimal Configuration

For pre-configured providers, this is all you need:

json
{
  "Auth": {
    "External": {
      "Enabled": true,
      "Google": {
        "Enabled": true,
        "ClientId": "{GOOGLE_CLIENT_ID}",
        "ClientSecret": "{GOOGLE_CLIENT_SECRET}"
      }
    }
  }
}

The AuthUrl, TokenUrl, InfoUrl, and EmailUrl settings are optional and only needed if:

  • The provider changes their endpoints
  • You need custom OAuth scopes
  • You're defining a custom provider not listed below

Google

Configure your app at Google Cloud Console.

Default URLs (for reference - you don't need to set these):

SettingDefault Value
AuthUrlhttps://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id={0}&redirect_uri={1}&scope=openid profile email&state={2}
TokenUrlhttps://oauth2.googleapis.com/token
InfoUrlhttps://www.googleapis.com/oauth2/v3/userinfo
EmailUrlnull

LinkedIn

Configure your app at LinkedIn Developers.

Default URLs (for reference - you don't need to set these):

SettingDefault Value
AuthUrlhttps://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id={0}&redirect_uri={1}&state={2}&scope=r_liteprofile%20r_emailaddress
TokenUrlhttps://www.linkedin.com/oauth/v2/accessToken
InfoUrlhttps://api.linkedin.com/v2/me
EmailUrlhttps://api.linkedin.com/v2/emailAddress?q=members&projection=(elements//(handle~))

GitHub

Configure your app at GitHub Developer Settings.

Default URLs (for reference - you don't need to set these):

SettingDefault Value
AuthUrlhttps://github.com/login/oauth/authorize?client_id={0}&redirect_uri={1}&state={2}&allow_signup=false
TokenUrlhttps://github.com/login/oauth/access_token
InfoUrlhttps://api.github.com/user
EmailUrlnull

Microsoft

Configure your app at Azure Portal. See Microsoft Identity Platform documentation.

Default URLs (for reference - you don't need to set these):

SettingDefault Value
AuthUrlhttps://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=code&client_id={0}&redirect_uri={1}&scope=openid%20profile%20email&state={2}
TokenUrlhttps://login.microsoftonline.com/common/oauth2/v2.0/token
InfoUrlhttps://graph.microsoft.com/oidc/userinfo
EmailUrlnull

Facebook

Configure your app at Facebook Developers. See Facebook Login documentation.

Default URLs (for reference - you don't need to set these):

SettingDefault Value
AuthUrlhttps://www.facebook.com/v20.0/dialog/oauth?response_type=code&client_id={0}&redirect_uri={1}&scope=public_profile%20email&state={2}
TokenUrlhttps://graph.facebook.com/v20.0/oauth/access_token
InfoUrlhttps://graph.facebook.com/me?fields=id,name,email
EmailUrlnull

Provider Settings Reference

Each provider has the same configuration options:

SettingTypeRequiredDescription
EnabledboolYesEnable this provider.
ClientIdstringYesOAuth client ID from the provider.
ClientSecretstringYesOAuth client secret from the provider.
AuthUrlstringNoAuthorization URL. Has sensible default for pre-configured providers. Placeholders: {0} = client ID, {1} = redirect URI, {2} = state.
TokenUrlstringNoToken exchange URL. Has sensible default for pre-configured providers.
InfoUrlstringNoUser info URL. Has sensible default for pre-configured providers.
EmailUrlstringNoEmail URL (some providers require separate request). Default is null.

Custom Providers

You can define custom OAuth providers by specifying all URL settings. Use any key name under External:

json
{
  "Auth": {
    "External": {
      "Enabled": true,
      "MyCustomProvider": {
        "Enabled": true,
        "ClientId": "your-client-id",
        "ClientSecret": "your-client-secret",
        "AuthUrl": "https://auth.example.com/oauth/authorize?response_type=code&client_id={0}&redirect_uri={1}&state={2}",
        "TokenUrl": "https://auth.example.com/oauth/token",
        "InfoUrl": "https://api.example.com/userinfo",
        "EmailUrl": null
      }
    }
  }
}

The sign-in URL will be /signin-mycustomprovider (provider name in lowercase).

Complete Example

Configuration with Google and GitHub OAuth:

json
{
  "Auth": {
    "CookieAuth": true,
    "CookieValidDays": 30,

    "External": {
      "Enabled": true,
      "ReturnToPath": "/dashboard",
      "LoginCommand": "select * from external_login($1, $2, $3, $4, $5)",

      "Google": {
        "Enabled": true,
        "ClientId": "{GOOGLE_CLIENT_ID}",
        "ClientSecret": "{GOOGLE_CLIENT_SECRET}"
      },

      "GitHub": {
        "Enabled": true,
        "ClientId": "{GITHUB_CLIENT_ID}",
        "ClientSecret": "{GITHUB_CLIENT_SECRET}"
      }
    }
  }
}

Next Steps

Comments

Released under the MIT License.