Skip to main content

GitLab

Let GitLab authenticate your users, then require membership in a selected group to reach your application. This guide works with GitLab.com or a GitLab instance you administer. It uses the named gitlab driver and its UserInfo group filter.

The example targets caddy-security v1.3.0, which bundles go-authcrunch v1.3.8. Configuration and local provider fixtures verify the released driver's behavior; your GitLab registration and consent flow still need an end-to-end check in your environment.

Before you start​

Complete Install and verify. Choose a public hostname for AuthCrunch, with ports 80 and 443 available for automatic HTTPS. The example uses auth.example.com; replace both occurrences in the Caddyfile and the callback below.

Have permission to register a GitLab OAuth application and select a group whose members should reach the protected app. This guide uses the full group path example-team/app-members. Use an existing path or create a group for your app. Plan a member and a nonmember account for testing.

Register the application​

In GitLab, open your profile's Access → Applications → Add new application, or visit https://gitlab.com/-/profile/applications. For Self-Managed, use your GitLab hostname instead. Group-owned applications are another option; see GitLab's application registration instructions.

SettingValue for this walkthrough
NameA recognizable name, such as Example team portal
Redirect URIhttps://auth.example.com/auth/oauth2/gitlab/authorization-code-callback
ConfidentialEnabled; the portal keeps the secret on the server
Scopesopenid, email, profile

Save the Application ID and Secret for the server environment. This login uses an OAuth application secret, not a personal access token. Repository write access and the broad api scope are unnecessary for this walkthrough.

GitLab application form with redirect URI and Confidential enabled

Earlier GitLab application screen. Use the public HTTPS callback above instead of the localhost value in this capture. Select the image to view it at full size.

GitLab application scopes with openid profile and email selected

The three selected identity scopes support this walkthrough; broader repository and API permissions are unnecessary. Select the image to view it at full size.

Configure AuthCrunch​

Save this complete configuration as Caddyfile. It is embedded from the canonical GitLab example.

Caddyfile
# Set the public portal hostname and GITLAB_DOMAIN before use.
{
admin off
persist_config off

security {
oauth identity provider gitlab {
driver gitlab
realm gitlab
client_id {env.GITLAB_CLIENT_ID}
client_secret {env.GITLAB_CLIENT_SECRET}
domain_name {$GITLAB_DOMAIN}
scopes openid email profile
user_group_filters ^example-team/app-members$
login icon text "GitLab"
}

authentication portal myportal {
enable identity provider gitlab
crypto default token lifetime 900
crypto key sign-verify {env.JWT_SHARED_KEY}
cookie path /

ui {
links {
"Example app" /app icon "las la-external-link-alt"
"My identity" /auth/whoami icon "las la-user"
}
}

transform user {
match realm gitlab
action add role authp/user
}

transform user {
match realm gitlab
match role {$GITLAB_DOMAIN}/example-team/app-members
action add role app/member
}
}

authorization policy apppolicy {
set auth url https://auth.example.com/auth/
crypto key verify {env.JWT_SHARED_KEY}
allow roles app/member
}
}
}

auth.example.com {
route {
redir /auth /auth/ 308

authenticate /auth/* with myportal

@app path /app /app/*
route @app {
authorize with apppolicy
respond "You reached the GitLab-protected app." 200
}

respond "AuthCrunch is running. Open /app to begin." 200
}
}

The first transform grants ordinary portal access. The second grants app/member only when the filtered GitLab group is present. The policy requires that application role for /app and every path underneath it. Replace the protected respond with reverse_proxy when connecting your own application.

Set the environment​

export GITLAB_DOMAIN='gitlab.com'
export GITLAB_CLIENT_ID='YOUR_APPLICATION_ID'
export GITLAB_CLIENT_SECRET='YOUR_APPLICATION_SECRET'
export JWT_SHARED_KEY="$(openssl rand -hex 32)"

For Self-Managed, set GITLAB_DOMAIN to your GitLab hostname, such as gitlab.example.com, without https:// or a trailing slash. The provider constructs its HTTPS discovery URL from that hostname. The AuthCrunch server must reach it and trust its TLS certificate.

{$GITLAB_DOMAIN} expands when Caddy parses the configuration, including the group-role prefix. The credentials and shared signing key use runtime {env.VARIABLE} placeholders. Keep those secrets in the protected environment of the process or service, and reuse the signing key across restarts.

Replace example-team/app-members in both the group filter and role matcher with your group's full path. Escape regex metacharacters in the filter if your path contains them. Retain the ^ and $ anchors for an exact path match.

Check and run​

Using your installed binary:

./bin/authcrunch adapt --adapter caddyfile --config Caddyfile >/dev/null
./bin/authcrunch run --config Caddyfile

Adaptation checks syntax, not your credentials or membership. The foreground process starts the portal and provisions HTTPS. This example disables the admin endpoint; stop it with Ctrl+C and restart after configuration changes.

Understand the group filter​

The gitlab driver exchanges the authorization code, then calls the discovered UserInfo endpoint with the access token. It takes group paths from that response's groups array. GitLab documents this array as including direct membership and membership through an ancestor group. It differs from the ID token's groups_direct claim. See GitLab's OIDC claims.

The path passes through two checks:

StageExample
GitLab UserInfo groupexample-team/app-members
Filter applied to the unprefixed path^example-team/app-members$
Role exposed to the portalgitlab.com/example-team/app-members
Transform grants application accessapp/member

With no user_group_filters, the named driver omits GitLab groups. The filter selects claims to retain; it does not itself deny sign-in. The application policy is the final access check. A subgroup such as example-team/app-members/child does not match this example's anchored filter.

For multiple accepted paths, put the regexes on one directive:

user_group_filters ^example-team/app-members$ ^example-team/app-operators$

Then add the corresponding role-granting transform for each path you intend to authorize. Multiple role-granting transforms are additive. Avoid broad filters such as .* unless every returned group is intended to become a portal role.

Identity fields​

The named driver uses the UserInfo profile URL as the AuthCrunch sub, not GitLab's numeric OIDC subject. A renamed GitLab username can change that profile URL. This walkthrough authorizes by the selected group, not username or email.

GitLab may omit email depending on the requested scope and the user's public email setting. The named GitLab path can still sign in without it; the group policy continues to apply. The generic driver's default ID-token email check is a different behavior. An ID-token groups_direct claim, or a group present only in the ID token, does not supply this named driver's group roles.

Verify login and denial​

  1. Open https://auth.example.com/app in a fresh browser session.
  2. Choose GitLab, sign in, and authorize the registered application.
  3. Open Example app from the portal. A group member should see You reached the GitLab-protected app.
  4. Open My identity at /auth/whoami. Check realm: gitlab, the prefixed group role, and app/member.
  5. In a separate session, sign in as a nonmember. Portal login can succeed, but /app must return 403 without the protected response.

Use a fresh login after changing group membership, filters, or transforms. Existing AuthCrunch tokens retain their recorded roles until they expire; this example uses a 900-second lifetime. Portal logout clears the portal session, while an existing GitLab browser session can still make the next login seamless.

Troubleshoot​

SymptomCheck
Provider fails to initializeHostname, discovery response, network access, and TLS trust for the GitLab instance
Callback rejectedExact HTTPS host and /auth/oauth2/gitlab/authorization-code-callback path in the OAuth application
Login succeeds but /app is 403Full group path, anchored filter, hostname prefix, and the user's actual UserInfo membership
Group appears in an ID token but not My identityThis driver consumes UserInfo groups, not ID-token groups_direct
Login fails while fetching claimsUserInfo must succeed and contain a profile field; a failed response is not a successful login
Access persists after removing membershipTest a new portal session; membership changes do not rewrite already-issued tokens

For explicit issuer/discovery configuration and ID-token claim handling, see the generic OIDC reference. Switching drivers changes the subject and group source; recheck your transforms before migrating.