Open-Source Wikis

/

GitLab

/

Systems

/

Authentication

gitlab-org/gitlab

Authentication

How GitLab decides who's calling.

Purpose

Validate session cookies, OAuth tokens, personal/project/group access tokens, deploy keys, SSH keys, JWT tokens (CI jobs), and federated identity providers.

Layers

graph TD
    Req[Incoming request]
    Devise[Devise<br/>session cookies]
    Doorkeeper[Doorkeeper<br/>OAuth2]
    OmniAuth[OmniAuth<br/>SSO providers]
    GitlabAuth[Gitlab::Auth<br/>token validation]
    JWT[JWT for CI/MCP]

    Req --> Devise
    Req --> Doorkeeper
    Req --> GitlabAuth
    Req --> JWT
    Doorkeeper --> User[(User)]
    Devise --> User
    OmniAuth --> Devise
    GitlabAuth --> User

Source layout

Concern Location
Session controller app/controllers/sessions_controller.rb
Devise customizations lib/gitlab/auth/, app/controllers/passwords_controller.rb, etc.
Doorkeeper (OAuth2) lib/api_authentication/, app/controllers/oauth/, mounted via config/routes.rb
OmniAuth app/controllers/omniauth_callbacks_controller.rb, lib/omni_auth/
Token validation lib/gitlab/auth.rb (~22K LoC)
Personal access tokens app/models/personal_access_token.rb, app/services/personal_access_tokens/
Group / Project access tokens app/services/group_access_tokens/, app/services/project_access_tokens/
CI job tokens lib/gitlab/auth/ci_job_token_scope/
JWT lib/json_web_token/, app/controllers/jwt_controller.rb
API guard lib/api/api_guard.rb
Internal API auth lib/api/helpers/internal/
Webauthn / U2F app/services/webauthn/, app/services/two_factor/
MCP discovery app/controllers/jwks_controller.rb (well-known endpoints)

EE adds:

  • SAML group sync (ee/lib/saml/).
  • SCIM (ee/lib/api/scim/).
  • Kerberos.
  • Identity verification (ee/lib/identity_verification/).
  • Beyond Identity integration (ee/lib/beyond_identity/).
  • Smartcard auth.

Token types

GitLab issues many flavors of token:

Token Holder Scope Created via
Personal Access Token (PAT) User API scopes Profile > Access tokens
Project Access Token Bot user attached to project Project-scoped Project > Access Tokens
Group Access Token Bot user attached to group Group-scoped Group > Access Tokens
Deploy Key SSH key tied to repo Read or read+write Per-project setting
Deploy Token username/password pair Registry/repository Per-project
CI Job Token Generated per running job CI job scope Auto
Runner Token Runner identity Runner registration Admin
Trigger Token Pipeline trigger Pipeline trigger Per-project
OAuth Access Token Doorkeeper-managed OAuth scopes OAuth flow
Impersonation Token Admin acting as user Per-grant scopes Admin only
Cluster Agent Token KAS agent Single agent Project

Gitlab::Auth::AuthFinders (lib/gitlab/auth/auth_finders.rb) inspects each request and picks the right token finder.

Auth flow for the REST API

sequenceDiagram
    Client->>API: GET /api/v4/projects/123 (Authorization: Bearer pat_xxx)
    API->>API: API::API mounted endpoint
    API->>Helpers: authenticate!
    Helpers->>Auth: Gitlab::Auth.find_with_user_password / find_personal_access_token
    Auth->>DB: lookup token, check scopes/expiry
    Auth-->>Helpers: User
    Helpers-->>API: current_user
    API-->>Client: project payload

SSH and Git over HTTPS

For SSH: GitLab Shell (separate repo) calls back into the Rails internal API at /api/v4/internal/allowed (lib/api/internal/base.rb). The internal API checks the SSH key against the user, the repo, and ability rules.

For HTTPS: Workhorse calls the same internal endpoint with the basic auth credentials.

OAuth2

Doorkeeper provides:

  • /oauth/authorize (oauth/authorizations_controller.rb).
  • /oauth/token (oauth/tokens_controller.rb).
  • Application registration UI.
  • OIDC discovery (/.well-known/openid-configuration) via JwksController.

Custom additions:

  • Dynamic registration (oauth/dynamic_registrations_controller.rb).
  • Device authorization grant.
  • Per-tenant MCP OAuth metadata endpoints (config/routes.rb).

Two-factor auth

Implemented in app/services/two_factor/ and app/services/webauthn/ plus controllers under app/controllers/profiles/two_factor_auths_controller.rb. Backed by:

  • TOTP (devise-two-factor gem).
  • WebAuthn (webauthn-ruby).
  • Recovery codes.

EE adds enforced 2FA at the group level and SAML group enforcement.

OmniAuth providers

config/initializers/omniauth.rb (and lib/omni_auth/) wire up:

  • Google, GitHub, GitLab.com, Bitbucket OAuth.
  • LDAP (gitlab_omniauth-ldap gem).
  • SAML (omniauth-saml).
  • Atlassian / Bitbucket Server.
  • Azure AD.
  • Many more.

The callback controller handles user lookup, JIT provisioning, identity linking, and 2FA enforcement.

Where to make changes

  • New token type: extend Gitlab::Auth and add a finder under app/finders/.
  • New OAuth scope: add to Gitlab::Auth::API_SCOPES and document in doc/api/oauth2.md.
  • New OmniAuth provider: register in config/initializers/omniauth.rb and add a strategy.
  • New 2FA factor: add a controller + service following webauthn patterns.
  • Authorization — what the user can do once authenticated.
  • Internal API — the auth callback shape used by Shell/KAS/Workhorse.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Authentication – GitLab wiki | Factory