Files
ThothII/install/authentication-oidc/index.html
T

218 lines
10 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="canonical" href="https://git.tylconsulting.it/thothii-docs/install/authentication-oidc/">
<link rel="shortcut icon" href="../../img/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<title>OIDC authentication - ThothII Docs</title>
<link href="../../css/bootstrap-3.3.7.min.css" rel="stylesheet">
<link href="../../css/font-awesome-4.7.0.css" rel="stylesheet">
<link href="../../css/base.css" rel="stylesheet">
<link rel="stylesheet" href="../../css/highlight.css">
<link href="../../stylesheets/extra.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
<script src="../../js/jquery-3.2.1.min.js"></script>
<script src="../../js/bootstrap-3.3.7.min.js"></script>
<script src="../../js/highlight.pack.js"></script>
<base target="_top">
<script>
var base_url = '../..';
var is_top_frame = false;
var pageToc = [
{title: "Generic OIDC authentication", url: "#_top", children: [
{title: "The groups claim is mandatory", url: "#the-groups-claim-is-mandatory" },
{title: "Checks and diagnostics", url: "#checks-and-diagnostics" },
{title: "Browser login and logout", url: "#browser-login-and-logout" },
]},
];
</script>
<script src="../../js/base.js"></script>
<script src="../../javascripts/layout-init.js"></script>
</head>
<body>
<script>
if (is_top_frame) { $('body').addClass('wm-top-page'); }
</script>
<div class="container-fluid wm-page-content">
<a name="_top"></a>
<div class="row wm-article-nav-buttons" role="navigation" aria-label="navigation">
<div class="wm-article-nav pull-right">
<a href="../authentik/" class="btn btn-xs btn-default pull-right">
Next
<i class="fa fa-chevron-right" aria-hidden="true"></i>
</a>
<a href="../authentik/" class="btn btn-xs btn-link">
Authentik
</a>
</div>
<div class="wm-article-nav">
<a href="../authentication-local/" class="btn btn-xs btn-default pull-left">
<i class="fa fa-chevron-left" aria-hidden="true"></i>
Previous</a><a href="../authentication-local/" class="btn btn-xs btn-link">
Local authentication
</a>
</div>
</div>
<h1 id="generic-oidc-authentication">Generic OIDC authentication<a class="headerlink" href="#generic-oidc-authentication" title="Permanent link">&para;</a></h1>
<p>Use this guide for <strong>ThothII's own login</strong>, normally <code>shell.mode: full</code> on an
autonomous server. It is not the integration procedure for an already logged-in
Omics user. That deployment uses <a href="../shell-and-language/">embedded/upstream</a>,
even when Omics's identity provider is Authentik.</p>
<p>OIDC mode supports a standards-based provider. The browser flow is generic: Authorization Code,
PKCE S256, state, nonce, issuer/signature/audience/expiry validation, and the fixed callback
<code>&lt;publicUrl&gt;/api/auth/oidc/callback</code>. The browser and API must use the same origin; configure the
reverse proxy to preserve that public origin and callback path.</p>
<p><code>publicUrl</code> is the public origin, without an application subpath. The current
full OIDC browser entry and callback use <code>/api/auth/oidc/login</code> and
<code>/api/auth/oidc/callback</code>; arbitrary prefixed OIDC hosting is not implemented by
selecting a different <code>backendBaseUrl</code>.</p>
<p>Configure the installation with <code>tht</code>:</p>
<pre class="highlight"><code class="language-sh">tht auth configure --mode oidc --public-url &lt;https-public-origin&gt; \
--issuer &lt;https-issuer&gt; --client-id &lt;client-id&gt; \
--authentik-base-url &lt;https-provider-origin&gt; \
--user-group 'TOT Users' --admin-group 'TOT Admin'</code></pre>
<p>The OIDC client secret is supplied through the protected secret bundle under the exact key
<code>THT_OIDC_CLIENT_SECRET</code>; it is never written into <code>auth.yaml</code>. The default scopes are exactly
<code>openid</code>, <code>profile</code>, and <code>email</code>.</p>
<p>Keep <code>AUTH_MODE</code> unset when using this file. A simultaneously mounted local/OIDC
configuration and <code>AUTH_MODE=upstream</code> is an error, not a fallback chain.</p>
<p>The non-secret OIDC configuration has this exact shape (replace angle-bracket placeholders with
operator values):</p>
<pre class="highlight"><code class="language-yaml">version: 1
mode: oidc
publicUrl: &lt;https-public-origin&gt;
session:
regularTtlSeconds: 43200
regularIdleSeconds: 7200
rememberTtlSeconds: 2592000
rememberIdleSeconds: 604800
oidcTtlSeconds: 28800
oidc:
issuer: &lt;https-issuer&gt;
clientId: &lt;client-id&gt;
clientSecretRef: THT_OIDC_CLIENT_SECRET
scopes: [openid, profile, email]
groupsClaim: groups
groupCatalog:
driver: authentik
baseUrl: &lt;https-provider-origin&gt;
apiTokenRef: THT_AUTHENTIK_API_TOKEN
authorization:
groupRoles:
TOT Users: [user]
TOT Admin: [admin]</code></pre>
<h2 id="the-groups-claim-is-mandatory">The groups claim is mandatory<a class="headerlink" href="#the-groups-claim-is-mandatory" title="Permanent link">&para;</a></h2>
<p>The ID token must contain a direct, non-empty <code>groups</code> array of strings. ThothII does not follow
distributed claims, overage links, or indirect provider expansion. Missing or malformed claims fail
closed. A browser callback exposes only HTTP 401 <code>oidc_callback_failed</code>; it never reveals whether
the claim was missing, malformed, indirect, or overage-style. The redacted diagnostic and
interactive device-flow contract uses <code>oidc_groups_claim_invalid</code> for invalid group-claim or
device-flow identity results.</p>
<p>Configured group names are exact and case-sensitive. The union of matched mappings determines the
Thoth roles. A token with no mapped group is authenticated but has no role and cannot use protected
routes. Additional provider groups are ignored silently, without an error or warning. Group
existence is separately proven by the configured catalog adapter; this is why a generic OIDC
provider may authenticate while still failing installation readiness.</p>
<h2 id="checks-and-diagnostics">Checks and diagnostics<a class="headerlink" href="#checks-and-diagnostics" title="Permanent link">&para;</a></h2>
<p>The surfaces have distinct semantics and this order is recommended:</p>
<ol>
<li>Workspace Validate performs static authentication validation without contacting the provider.</li>
<li><code>tht auth check</code> performs live, non-interactive authentication diagnosis, including discovery,
issuer/JWKS, catalog credentials, and all configured mapped groups.</li>
<li><code>tht auth check --interactive</code> repeats live diagnosis and additionally validates a device-flow
identity and its direct <code>groups</code> claim when Device Authorization is available.</li>
<li>Installation diagnostics perform aggregate live workspace and authentication validation.</li>
</ol>
<p>The live CLI forms are:</p>
<pre class="highlight"><code class="language-sh">tht auth check
tht auth check --json</code></pre>
<p>For a provider that advertises Device Authorization, <code>tht auth check --interactive</code> presents a
verification URI and one-time user code on the terminal, waits for completion, and validates a
real ID token including <code>groups</code>. It is an operator check, not a replacement for browser login.</p>
<p><code>tht doctor</code> emits this exact ordered report: <code>descriptor</code>, <code>files</code>, <code>docker</code>, <code>compose</code>,
<code>configuration</code>, <code>authentication</code>, <code>services</code>, <code>core-http</code>, <code>frontend-http</code>,
<code>workspace-registry</code>, <code>workflow</code>, <code>pi</code>. Its authentication entry is live and non-interactive.
Any authentication failure prevents activation according to the static or live scope of the
relevant diagnostic surface.</p>
<p>The complete closed diagnostic-code union and exact role-to-permission expansion are in the
<a href="https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/architecture/authentication.md">authentication architecture</a>.</p>
<h2 id="browser-login-and-logout">Browser login and logout<a class="headerlink" href="#browser-login-and-logout" title="Permanent link">&para;</a></h2>
<p>ThothII redirects the browser to the provider and creates its own opaque session
after validating the callback. An existing provider SSO session may avoid another
password prompt, but this remains a distinct ThothII login/session, unlike Omics
upstream. Full's name menu logs out of ThothII only. It does not revoke the
provider session or log out other applications, so a subsequent login can return
immediately through SSO. No provider token is placed in the UI adapter or browser
storage. See the <a href="https://git.tylconsulting.it/mptyl/ThothII/src/branch/main/docs/testing/authentication-manual-acceptance.md">manual acceptance matrix</a>.</p>
<br>
<div class="row wm-article-nav-buttons" role="navigation" aria-label="navigation">
<div class="wm-article-nav pull-right">
<a href="../authentik/" class="btn btn-xs btn-default pull-right">
Next
<i class="fa fa-chevron-right" aria-hidden="true"></i>
</a>
<a href="../authentik/" class="btn btn-xs btn-link">
Authentik
</a>
</div>
<div class="wm-article-nav">
<a href="../authentication-local/" class="btn btn-xs btn-default pull-left">
<i class="fa fa-chevron-left" aria-hidden="true"></i>
Previous</a><a href="../authentication-local/" class="btn btn-xs btn-link">
Local authentication
</a>
</div>
</div>
<br>
</div>
<footer class="container-fluid wm-page-content">
<p>Documentation built with <a href="https://www.mkdocs.org/">MkDocs</a> using <a href="https://github.com/gristlabs/mkdocs-windmill">Windmill</a> theme by Grist Labs.</p>
</footer>
</body>
</html>