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 --> UserSource 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 payloadSSH 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) viaJwksController.
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-factorgem). - 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-ldapgem). - 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::Authand add a finder underapp/finders/. - New OAuth scope: add to
Gitlab::Auth::API_SCOPESand document indoc/api/oauth2.md. - New OmniAuth provider: register in
config/initializers/omniauth.rband add a strategy. - New 2FA factor: add a controller + service following webauthn patterns.
Related
- 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.