1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>32.20. OAuth Support</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /><link rel="prev" href="libpq-ssl.html" title="32.19. SSL Support" /><link rel="next" href="libpq-threading.html" title="32.21. Behavior in Threaded Programs" /></head><body id="docContent" class="container-fluid col-10"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">32.20. OAuth Support</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="libpq-ssl.html" title="32.19. SSL Support">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="libpq.html" title="Chapter 32. libpq — C Library">Up</a></td><th width="60%" align="center">Chapter 32. <span class="application">libpq</span> — C Library</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="libpq-threading.html" title="32.21. Behavior in Threaded Programs">Next</a></td></tr></table><hr /></div><div class="sect1" id="LIBPQ-OAUTH"><div class="titlepage"><div><div><h2 class="title" style="clear: both">32.20. OAuth Support <a href="#LIBPQ-OAUTH" class="id_link">#</a></h2></div></div></div><div class="toc"><dl class="toc"><dt><span class="sect2"><a href="libpq-oauth.html#LIBPQ-OAUTH-AUTHDATA-HOOKS">32.20.1. Authdata Hooks</a></span></dt><dt><span class="sect2"><a href="libpq-oauth.html#LIBPQ-OAUTH-DEBUGGING">32.20.2. Debugging and Developer Settings</a></span></dt></dl></div><p>
3 <span class="application">libpq</span> implements support for the OAuth v2 Device Authorization client flow,
5 <a class="ulink" href="https://datatracker.ietf.org/doc/html/rfc8628" target="_top">RFC 8628</a>,
6 as an optional module. See the <a class="link" href="install-make.html#CONFIGURE-OPTION-WITH-LIBCURL">
7 installation documentation</a> for information on how to enable support
8 for Device Authorization as a builtin flow.
10 When support is enabled and the optional module installed, <span class="application">libpq</span>
11 will use the builtin flow by default if the server
12 <a class="link" href="auth-oauth.html" title="20.15. OAuth Authorization/Authentication">requests a bearer token</a> during
13 authentication. This flow can be utilized even if the system running the
14 client application does not have a usable web browser, for example when
15 running a client via <acronym class="acronym">SSH</acronym>.
17 The builtin flow will, by default, print a URL to visit and a user code to
19 </p><pre class="programlisting">
20 $ psql 'dbname=postgres oauth_issuer=https://example.com oauth_client_id=...'
21 Visit https://example.com/device and enter the code: ABCD-EFGH
24 <a class="link" href="libpq-oauth.html#LIBPQ-OAUTH-AUTHDATA-PROMPT-OAUTH-DEVICE">customized</a>.)
25 The user will then log into their OAuth provider, which will ask whether
26 to allow libpq and the server to perform actions on their behalf. It is always
27 a good idea to carefully review the URL and permissions displayed, to ensure
28 they match expectations, before continuing. Permissions should not be given
29 to untrusted third parties.
31 Client applications may implement their own flows to customize interaction
32 and integration with applications. See <a class="xref" href="libpq-oauth.html#LIBPQ-OAUTH-AUTHDATA-HOOKS" title="32.20.1. Authdata Hooks">Section 32.20.1</a>
33 for more information on how add a custom flow to <span class="application">libpq</span>.
35 For an OAuth client flow to be usable, the connection string must at minimum
36 contain <a class="xref" href="libpq-connect.html#LIBPQ-CONNECT-OAUTH-ISSUER">oauth_issuer</a> and
37 <a class="xref" href="libpq-connect.html#LIBPQ-CONNECT-OAUTH-CLIENT-ID">oauth_client_id</a>. (These settings are
38 determined by your organization's OAuth provider.) The builtin flow
39 additionally requires the OAuth authorization server to publish a device
40 authorization endpoint.
41 </p><div class="note"><h3 class="title">Note</h3><p>
42 The builtin Device Authorization flow is not currently supported on Windows.
43 Custom client flows may still be implemented.
44 </p></div><div class="sect2" id="LIBPQ-OAUTH-AUTHDATA-HOOKS"><div class="titlepage"><div><div><h3 class="title">32.20.1. Authdata Hooks <a href="#LIBPQ-OAUTH-AUTHDATA-HOOKS" class="id_link">#</a></h3></div></div></div><p>
45 The behavior of the OAuth flow may be modified or replaced by a client using
46 the following hook API:
48 </p><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PQSETAUTHDATAHOOK"><span class="term"><code class="function">PQsetAuthDataHook</code><a id="id-1.7.3.27.8.2.1.1.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PQSETAUTHDATAHOOK" class="id_link">#</a></dt><dd><p>
49 Sets the <code class="symbol">PGauthDataHook</code>, overriding
50 <span class="application">libpq</span>'s handling of one or more aspects of
51 its OAuth client flow.
52 </p><pre class="synopsis">
53 void PQsetAuthDataHook(PQauthDataHook_type hook);
55 If <em class="replaceable"><code>hook</code></em> is <code class="literal">NULL</code>, the
56 default handler will be reinstalled. Otherwise, the application passes
57 a pointer to a callback function with the signature:
58 </p><pre class="programlisting">
59 int hook_fn(PGauthData type, PGconn *conn, void *data);
61 which <span class="application">libpq</span> will call when an action is
62 required of the application. <em class="replaceable"><code>type</code></em> describes
63 the request being made, <em class="replaceable"><code>conn</code></em> is the
64 connection handle being authenticated, and <em class="replaceable"><code>data</code></em>
65 points to request-specific metadata. The contents of this pointer are
66 determined by <em class="replaceable"><code>type</code></em>; see
67 <a class="xref" href="libpq-oauth.html#LIBPQ-OAUTH-AUTHDATA-HOOKS-TYPES" title="32.20.1.1. Hook Types">Section 32.20.1.1</a> for the supported
70 Hooks can be chained together to allow cooperative and/or fallback
71 behavior. In general, a hook implementation should examine the incoming
72 <em class="replaceable"><code>type</code></em> (and, potentially, the request metadata
73 and/or the settings for the particular <em class="replaceable"><code>conn</code></em>
74 in use) to decide whether or not to handle a specific piece of authdata.
75 If not, it should delegate to the previous hook in the chain
76 (retrievable via <code class="function">PQgetAuthDataHook</code>).
78 Success is indicated by returning an integer greater than zero.
79 Returning a negative integer signals an error condition and abandons the
80 connection attempt. (A zero value is reserved for the default
82 </p></dd><dt id="LIBPQ-PQGETAUTHDATAHOOK"><span class="term"><code class="function">PQgetAuthDataHook</code><a id="id-1.7.3.27.8.2.1.2.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PQGETAUTHDATAHOOK" class="id_link">#</a></dt><dd><p>
83 Retrieves the current value of <code class="symbol">PGauthDataHook</code>.
84 </p><pre class="synopsis">
85 PQauthDataHook_type PQgetAuthDataHook(void);
87 At initialization time (before the first call to
88 <code class="function">PQsetAuthDataHook</code>), this function will return
89 <code class="symbol">PQdefaultAuthDataHook</code>.
90 </p></dd></dl></div><p>
91 </p><div class="sect3" id="LIBPQ-OAUTH-AUTHDATA-HOOKS-TYPES"><div class="titlepage"><div><div><h4 class="title">32.20.1.1. Hook Types <a href="#LIBPQ-OAUTH-AUTHDATA-HOOKS-TYPES" class="id_link">#</a></h4></div></div></div><p>
92 The following <code class="symbol">PGauthData</code> types and their corresponding
93 <em class="replaceable"><code>data</code></em> structures are defined:
95 </p><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-OAUTH-AUTHDATA-PROMPT-OAUTH-DEVICE"><span class="term">
96 <code class="symbol">PQAUTHDATA_PROMPT_OAUTH_DEVICE</code>
97 <a id="id-1.7.3.27.8.3.2.3.1.1.2" class="indexterm"></a>
98 </span> <a href="#LIBPQ-OAUTH-AUTHDATA-PROMPT-OAUTH-DEVICE" class="id_link">#</a></dt><dd><p>
99 Replaces the default user prompt during the builtin device
100 authorization client flow. <em class="replaceable"><code>data</code></em> points to
101 an instance of <code class="symbol">PGpromptOAuthDevice</code>:
102 </p><pre class="synopsis">
103 typedef struct _PGpromptOAuthDevice
105 const char *verification_uri; /* verification URI to visit */
106 const char *user_code; /* user code to enter */
107 const char *verification_uri_complete; /* optional combination of URI and
109 int expires_in; /* seconds until user code expires */
110 } PGpromptOAuthDevice;
113 The OAuth Device Authorization flow which
114 <a class="link" href="install-make.html#CONFIGURE-OPTION-WITH-LIBCURL">can be included</a>
115 in <span class="application">libpq</span>
116 requires the end user to visit a URL with a browser, then enter a code
117 which permits <span class="application">libpq</span> to connect to the server
118 on their behalf. The default prompt simply prints the
119 <code class="literal">verification_uri</code> and <code class="literal">user_code</code>
120 on standard error. Replacement implementations may display this
121 information using any preferred method, for example with a GUI.
123 This callback is only invoked during the builtin device
124 authorization flow. If the application installs a
125 <a class="link" href="libpq-oauth.html#LIBPQ-OAUTH-AUTHDATA-OAUTH-BEARER-TOKEN">custom OAuth
126 flow</a>, or <span class="application">libpq</span> was not built with
127 support for the builtin flow, this authdata type will not be used.
129 If a non-NULL <code class="structfield">verification_uri_complete</code> is
130 provided, it may optionally be used for non-textual verification (for
131 example, by displaying a QR code). The URL and user code should still
132 be displayed to the end user in this case, because the code will be
133 manually confirmed by the provider, and the URL lets users continue
134 even if they can't use the non-textual method. For more information,
136 <a class="ulink" href="https://datatracker.ietf.org/doc/html/rfc8628#section-3.3.1" target="_top">RFC 8628</a>.
137 </p></dd><dt id="LIBPQ-OAUTH-AUTHDATA-OAUTH-BEARER-TOKEN"><span class="term">
138 <code class="symbol">PQAUTHDATA_OAUTH_BEARER_TOKEN</code>
139 <a id="id-1.7.3.27.8.3.2.3.2.1.2" class="indexterm"></a>
140 </span> <a href="#LIBPQ-OAUTH-AUTHDATA-OAUTH-BEARER-TOKEN" class="id_link">#</a></dt><dd><p>
141 Adds a custom implementation of a flow, replacing the builtin flow if
142 it is <a class="link" href="install-make.html#CONFIGURE-OPTION-WITH-LIBCURL">installed</a>.
143 The hook should either directly return a Bearer token for the current
144 user/issuer/scope combination, if one is available without blocking, or
145 else set up an asynchronous callback to retrieve one.
147 <em class="replaceable"><code>data</code></em> points to an instance
148 of <code class="symbol">PGoauthBearerRequest</code>, which should be filled in
149 by the implementation:
150 </p><pre class="synopsis">
151 typedef struct PGoauthBearerRequest
153 /* Hook inputs (constant across all calls) */
154 const char *openid_configuration; /* OIDC discovery URL */
155 const char *scope; /* required scope(s), or NULL */
159 /* Callback implementing a custom asynchronous OAuth flow. */
160 PostgresPollingStatusType (*async) (PGconn *conn,
161 struct PGoauthBearerRequest *request,
164 /* Callback to clean up custom allocations. */
165 void (*cleanup) (PGconn *conn, struct PGoauthBearerRequest *request);
167 char *token; /* acquired Bearer token */
168 void *user; /* hook-defined allocated data */
169 } PGoauthBearerRequest;
172 Two pieces of information are provided to the hook by
173 <span class="application">libpq</span>:
174 <em class="replaceable"><code>openid_configuration</code></em> contains the URL of an
175 OAuth discovery document describing the authorization server's
176 supported flows, and <em class="replaceable"><code>scope</code></em> contains a
177 (possibly empty) space-separated list of OAuth scopes which are
178 required to access the server. Either or both may be
179 <code class="literal">NULL</code> to indicate that the information was not
180 discoverable. (In this case, implementations may be able to establish
181 the requirements using some other preconfigured knowledge, or they may
184 The final output of the hook is <em class="replaceable"><code>token</code></em>, which
185 must point to a valid Bearer token for use on the connection. (This
186 token should be issued by the
187 <a class="xref" href="libpq-connect.html#LIBPQ-CONNECT-OAUTH-ISSUER">oauth_issuer</a> and hold the requested
188 scopes, or the connection will be rejected by the server's validator
189 module.) The allocated token string must remain valid until
190 <span class="application">libpq</span> is finished connecting; the hook
191 should set a <em class="replaceable"><code>cleanup</code></em> callback which will be
192 called when <span class="application">libpq</span> no longer requires it.
194 If an implementation cannot immediately produce a
195 <em class="replaceable"><code>token</code></em> during the initial call to the hook,
196 it should set the <em class="replaceable"><code>async</code></em> callback to handle
197 nonblocking communication with the authorization server.
198 <a href="#ftn.id-1.7.3.27.8.3.2.3.2.2.5.3" class="footnote"><sup class="footnote" id="id-1.7.3.27.8.3.2.3.2.2.5.3">[16]</sup></a>
199 This will be called to begin the flow immediately upon return from the
200 hook. When the callback cannot make further progress without blocking,
201 it should return either <code class="symbol">PGRES_POLLING_READING</code> or
202 <code class="symbol">PGRES_POLLING_WRITING</code> after setting
203 <code class="literal">*pgsocket</code> to the file descriptor that will be marked
204 ready to read/write when progress can be made again. (This descriptor
205 is then provided to the top-level polling loop via
206 <code class="function">PQsocket()</code>.) Return <code class="symbol">PGRES_POLLING_OK</code>
207 after setting <em class="replaceable"><code>token</code></em> when the flow is
208 complete, or <code class="symbol">PGRES_POLLING_FAILED</code> to indicate failure.
210 Implementations may wish to store additional data for bookkeeping
211 across calls to the <em class="replaceable"><code>async</code></em> and
212 <em class="replaceable"><code>cleanup</code></em> callbacks. The
213 <em class="replaceable"><code>user</code></em> pointer is provided for this purpose;
214 <span class="application">libpq</span> will not touch its contents and the
215 application may use it at its convenience. (Remember to free any
216 allocations during token cleanup.)
217 </p></dd></dl></div><p>
218 </p></div></div><div class="sect2" id="LIBPQ-OAUTH-DEBUGGING"><div class="titlepage"><div><div><h3 class="title">32.20.2. Debugging and Developer Settings <a href="#LIBPQ-OAUTH-DEBUGGING" class="id_link">#</a></h3></div></div></div><p>
219 A "dangerous debugging mode" may be enabled by setting the environment
220 variable <code class="envar">PGOAUTHDEBUG=UNSAFE</code>. This functionality is provided
221 for ease of local development and testing only. It does several things that
222 you will not want a production system to do:
224 </p><div class="itemizedlist"><ul class="itemizedlist compact" style="list-style-type: disc; "><li class="listitem"><p>
225 permits the use of unencrypted HTTP during the OAuth provider exchange
226 </p></li><li class="listitem"><p>
227 allows the system's trusted CA list to be completely replaced using the
228 <code class="envar">PGOAUTHCAFILE</code> environment variable
229 </p></li><li class="listitem"><p>
230 prints HTTP traffic (containing several critical secrets) to standard
231 error during the OAuth flow
232 </p></li><li class="listitem"><p>
233 permits the use of zero-second retry intervals, which can cause the
234 client to busy-loop and pointlessly consume CPU
235 </p></li></ul></div><p>
236 </p><div class="warning"><h3 class="title">Warning</h3><p>
237 Do not share the output of the OAuth flow traffic with third parties. It
238 contains secrets that can be used to attack your clients and servers.
239 </p></div></div><div class="footnotes"><br /><hr style="width:100; text-align:left;margin-left: 0" /><div id="ftn.id-1.7.3.27.8.3.2.3.2.2.5.3" class="footnote"><p><a href="#id-1.7.3.27.8.3.2.3.2.2.5.3" class="para"><sup class="para">[16] </sup></a>
240 Performing blocking operations during the
241 <code class="symbol">PQAUTHDATA_OAUTH_BEARER_TOKEN</code> hook callback will
242 interfere with nonblocking connection APIs such as
243 <code class="function">PQconnectPoll</code> and prevent concurrent connections
244 from making progress. Applications which only ever use the
245 synchronous connection primitives, such as
246 <code class="function">PQconnectdb</code>, may synchronously retrieve a token
247 during the hook instead of implementing the
248 <em class="replaceable"><code>async</code></em> callback, but they will necessarily
249 be limited to one connection at a time.
250 </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="libpq-ssl.html" title="32.19. SSL Support">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="libpq.html" title="Chapter 32. libpq — C Library">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="libpq-threading.html" title="32.21. Behavior in Threaded Programs">Next</a></td></tr><tr><td width="40%" align="left" valign="top">32.19. SSL Support </td><td width="20%" align="center"><a accesskey="h" href="index.html" title="PostgreSQL 18.0 Documentation">Home</a></td><td width="40%" align="right" valign="top"> 32.21. Behavior in Threaded Programs</td></tr></table></div></body></html>