# GitLab Authentication Reference ## Overview GitLab supports multiple authentication methods for accessing the API, Git repositories, and the web interface. ## Authentication Methods ### 1. Personal Access Tokens (PATs) Most common method for API and Git authentication. #### Creating a Personal Access Token **Via UI**: 1. Navigate to User Settings > Access Tokens 2. Enter token name 3. Set expiration date (optional but recommended) 4. Select scopes 5. Click "Create personal access token" 6. Copy token (shown only once) **Scopes**: - `api` - Complete API access - `read_api` - Read-only API access - `read_user` - Read user information - `read_repository` - Read repository (pull code) - `write_repository` - Write repository (push code) - `read_registry` - Read container registry - `write_registry` - Write container registry - `sudo` - Perform actions as any user (admin only) - `admin_mode` - Admin mode access #### Using Personal Access Tokens **API requests**: ```bash # Header method (preferred) curl --header "PRIVATE-TOKEN: " "https://gitlab.com/api/v4/projects" # Query parameter method curl "https://gitlab.com/api/v4/projects?private_token=" ``` **Git operations**: ```bash # Clone with token git clone https://oauth2:@gitlab.com/username/project.git # Or configure credential helper git config --global credential.helper store # Then use token as password when prompted ``` **Python example**: ```python import requests token = "your_access_token" headers = {"PRIVATE-TOKEN": token} response = requests.get( "https://gitlab.com/api/v4/projects", headers=headers ) print(response.json()) ``` #### Token Best Practices - Set expiration dates on all tokens - Use minimal required scopes - Store tokens securely (environment variables, secret managers) - Rotate tokens regularly - Revoke unused tokens - Never commit tokens to repositories ### 2. OAuth 2.0 OAuth 2.0 for third-party application authorization. #### OAuth Application Setup **Create OAuth Application**: 1. Navigate to User Settings > Applications 2. Enter application name 3. Set redirect URI 4. Select scopes 5. Click "Save application" 6. Note Application ID and Secret **Authorization Code Flow**: ```python import requests from flask import Flask, request, redirect app = Flask(__name__) CLIENT_ID = "your_client_id" CLIENT_SECRET = "your_client_secret" REDIRECT_URI = "http://localhost:5000/callback" GITLAB_URL = "https://gitlab.com" @app.route('/login') def login(): """Redirect user to GitLab authorization page""" auth_url = ( f"{GITLAB_URL}/oauth/authorize?" f"client_id={CLIENT_ID}&" f"redirect_uri={REDIRECT_URI}&" f"response_type=code&" f"scope=read_user+api" ) return redirect(auth_url) @app.route('/callback') def callback(): """Handle OAuth callback""" code = request.args.get('code') # Exchange code for access token token_response = requests.post( f"{GITLAB_URL}/oauth/token", data={ 'client_id': CLIENT_ID, 'client_secret': CLIENT_SECRET, 'code': code, 'grant_type': 'authorization_code', 'redirect_uri': REDIRECT_URI } ) token_data = token_response.json() access_token = token_data['access_token'] refresh_token = token_data['refresh_token'] # Use access token for API requests headers = {'Authorization': f'Bearer {access_token}'} user_response = requests.get( f"{GITLAB_URL}/api/v4/user", headers=headers ) return user_response.json() if __name__ == '__main__': app.run(port=5000) ``` **Refreshing Access Token**: ```python def refresh_access_token(refresh_token): response = requests.post( f"{GITLAB_URL}/oauth/token", data={ 'client_id': CLIENT_ID, 'client_secret': CLIENT_SECRET, 'refresh_token': refresh_token, 'grant_type': 'refresh_token', 'redirect_uri': REDIRECT_URI } ) return response.json() ``` #### OAuth Scopes - `api` - Full API access - `read_user` - Read user information - `read_api` - Read-only API access - `read_repository` - Read repositories - `write_repository` - Write to repositories - `read_registry` - Read container registry - `write_registry` - Write container registry - `sudo` - Admin impersonation (admin only) - `openid` - OpenID Connect - `profile` - User profile info - `email` - User email ### 3. SSH Keys SSH keys for Git operations. #### Generating SSH Keys ```bash # Generate new SSH key ssh-keygen -t ed25519 -C "your_email@example.com" # Or RSA (if ed25519 not supported) ssh-keygen -t rsa -b 4096 -C "your_email@example.com" # Start SSH agent eval "$(ssh-agent -s)" # Add key to agent ssh-add ~/.ssh/id_ed25519 ``` #### Adding SSH Key to GitLab **Via UI**: 1. Navigate to User Settings > SSH Keys 2. Paste public key content (`~/.ssh/id_ed25519.pub`) 3. Set title 4. Optional: Set expiration date 5. Click "Add key" **Via API**: ```bash curl --request POST --header "PRIVATE-TOKEN: " \ --data "title=My SSH Key" \ --data "key=$(cat ~/.ssh/id_ed25519.pub)" \ "https://gitlab.com/api/v4/user/keys" ``` #### Using SSH Keys ```bash # Clone with SSH git clone git@gitlab.com:username/project.git # Configure Git to use SSH git remote set-url origin git@gitlab.com:username/project.git # Test SSH connection ssh -T git@gitlab.com ``` #### SSH Key Best Practices - Use Ed25519 keys (more secure, faster) - Set passphrase on private keys - Use separate keys for different purposes - Set expiration dates - Store private keys securely - Never share private keys ### 4. Deploy Keys Read-only or read-write SSH keys for specific projects. #### Creating Deploy Keys **Via UI**: 1. Navigate to Project Settings > Repository > Deploy Keys 2. Enter title and key content 3. Check "Grant write permissions" if needed 4. Click "Add key" **Via API**: ```bash curl --request POST --header "PRIVATE-TOKEN: " \ --data "title=Deploy Key" \ --data "key=$(cat ~/.ssh/deploy_key.pub)" \ --data "can_push=false" \ "https://gitlab.com/api/v4/projects/:id/deploy_keys" ``` #### Deploy Key Use Cases - CI/CD pipelines - Deployment scripts - Automated processes - Read-only repository access ### 5. Deploy Tokens Project or group-level tokens for registry and package access. #### Creating Deploy Tokens **Via UI**: 1. Navigate to Project/Group Settings > Repository > Deploy Tokens 2. Enter name 3. Set expiration date 4. Select scopes: - `read_repository` - Clone repositories - `read_registry` - Pull container images - `write_registry` - Push container images - `read_package_registry` - Pull packages - `write_package_registry` - Push packages 5. Click "Create deploy token" 6. Copy username and token **Via API**: ```bash curl --request POST --header "PRIVATE-TOKEN: " \ --header "Content-Type: application/json" \ --data '{ "name": "My Deploy Token", "expires_at": "2025-12-31", "scopes": ["read_repository", "read_registry"] }' \ "https://gitlab.com/api/v4/projects/:id/deploy_tokens" ``` #### Using Deploy Tokens **Clone repository**: ```bash git clone https://:@gitlab.com/group/project.git ``` **Pull Docker image**: ```bash docker login -u -p registry.gitlab.com docker pull registry.gitlab.com/group/project/image:tag ``` **CI/CD**: ```yaml docker-build: script: - docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY - docker pull $CI_REGISTRY_IMAGE:latest ``` ### 6. Job Tokens (CI/CD) Temporary tokens for CI/CD job authentication. #### Using CI_JOB_TOKEN **API requests in CI**: ```yaml test-api: script: - | curl --header "JOB-TOKEN: $CI_JOB_TOKEN" \ "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID" ``` **Clone other repositories**: ```yaml build: script: - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/group/project.git ``` **Pull Docker images**: ```yaml build: before_script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY script: - docker pull $CI_REGISTRY_IMAGE:latest ``` #### Job Token Scope Configure which projects can be accessed: 1. Navigate to Settings > CI/CD > Token Access 2. Add allowed projects 3. Enable/disable token access ### 7. Project Access Tokens Project-level tokens for automation. #### Creating Project Access Tokens **Via UI**: 1. Navigate to Project Settings > Access Tokens 2. Enter token name 3. Set expiration date 4. Select role (Guest, Reporter, Developer, Maintainer) 5. Select scopes 6. Click "Create project access token" **Via API**: ```bash curl --request POST --header "PRIVATE-TOKEN: " \ --header "Content-Type: application/json" \ --data '{ "name": "Project Token", "scopes": ["api"], "access_level": 40, "expires_at": "2025-12-31" }' \ "https://gitlab.com/api/v4/projects/:id/access_tokens" ``` **Access Levels**: - 10: Guest - 20: Reporter - 30: Developer - 40: Maintainer - 50: Owner ### 8. Group Access Tokens Group-level tokens for all group projects. #### Creating Group Access Tokens **Via UI**: 1. Navigate to Group Settings > Access Tokens 2. Configure token (similar to project tokens) 3. Token applies to all group projects **Via API**: ```bash curl --request POST --header "PRIVATE-TOKEN: " \ --header "Content-Type: application/json" \ --data '{ "name": "Group Token", "scopes": ["api"], "access_level": 40 }' \ "https://gitlab.com/api/v4/groups/:id/access_tokens" ``` ### 9. LDAP Authentication Enterprise edition feature for LDAP/Active Directory integration. #### LDAP Configuration **`/etc/gitlab/gitlab.rb`**: ```ruby gitlab_rails['ldap_enabled'] = true gitlab_rails['ldap_servers'] = YAML.load <<-EOS main: label: 'LDAP' host: 'ldap.example.com' port: 636 uid: 'sAMAccountName' encryption: 'simple_tls' verify_certificates: true bind_dn: 'CN=query user,OU=Users,DC=example,DC=com' password: 'password' active_directory: true base: 'OU=Users,DC=example,DC=com' user_filter: '(memberOf=CN=GitLab Users,OU=Groups,DC=example,DC=com)' EOS ``` ### 10. SAML Authentication Enterprise edition SAML SSO support. #### SAML Configuration **`/etc/gitlab/gitlab.rb`**: ```ruby gitlab_rails['omniauth_enabled'] = true gitlab_rails['omniauth_allow_single_sign_on'] = ['saml'] gitlab_rails['omniauth_block_auto_created_users'] = false gitlab_rails['omniauth_providers'] = [ { name: 'saml', args: { assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', idp_cert_fingerprint: 'XX:XX:XX...', idp_sso_target_url: 'https://idp.example.com/sso', issuer: 'https://gitlab.example.com', name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' }, label: 'Company SSO' } ] ``` ## Security Best Practices ### Token Management 1. **Minimize Scope**: Use least privilege principle 2. **Set Expiration**: Always set token expiration dates 3. **Rotate Regularly**: Rotate tokens on schedule 4. **Secure Storage**: Use secret managers (Vault, AWS Secrets Manager) 5. **Monitor Usage**: Audit token usage regularly 6. **Revoke Unused**: Remove tokens no longer needed ### Secure Token Storage **Environment Variables**: ```bash export GITLAB_TOKEN="your_token" ``` **Git Credentials**: ```bash # Store credentials securely git config --global credential.helper 'cache --timeout=3600' ``` **Python example**: ```python import os from dotenv import load_dotenv load_dotenv() GITLAB_TOKEN = os.getenv('GITLAB_TOKEN') ``` **Docker Secrets**: ```bash echo "your_token" | docker secret create gitlab_token - ``` ### Two-Factor Authentication (2FA) #### Enabling 2FA 1. Navigate to User Settings > Account > Two-Factor Authentication 2. Scan QR code with authenticator app 3. Enter verification code 4. Save recovery codes securely #### Using 2FA with Git When 2FA is enabled, use: - Personal access tokens instead of passwords - SSH keys for Git operations ```bash # Use token as password git clone https://oauth2:@gitlab.com/username/project.git ``` ### IP Allowlisting Restrict API access by IP address (Premium/Ultimate). **Group/Instance Settings**: 1. Navigate to Settings > General > Allowed IP addresses 2. Add IP ranges 3. Save changes ## API Authentication Examples ### Python (requests library) ```python import requests class GitLabClient: def __init__(self, token, base_url="https://gitlab.com"): self.token = token self.base_url = base_url self.headers = {"PRIVATE-TOKEN": token} def get(self, endpoint): url = f"{self.base_url}/api/v4/{endpoint}" response = requests.get(url, headers=self.headers) response.raise_for_status() return response.json() def post(self, endpoint, data): url = f"{self.base_url}/api/v4/{endpoint}" response = requests.post(url, headers=self.headers, json=data) response.raise_for_status() return response.json() # Usage client = GitLabClient(token="your_token") projects = client.get("projects") ``` ### JavaScript (fetch API) ```javascript class GitLabClient { constructor(token, baseURL = 'https://gitlab.com') { this.token = token; this.baseURL = baseURL; } async get(endpoint) { const response = await fetch(`${this.baseURL}/api/v4/${endpoint}`, { headers: { 'PRIVATE-TOKEN': this.token } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } async post(endpoint, data) { const response = await fetch(`${this.baseURL}/api/v4/${endpoint}`, { method: 'POST', headers: { 'PRIVATE-TOKEN': this.token, 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } } // Usage const client = new GitLabClient('your_token'); const projects = await client.get('projects'); ``` ### Go ```go package main import ( "fmt" "github.com/xanzy/go-gitlab" ) func main() { git, err := gitlab.NewClient("your_token") if err != nil { panic(err) } // List projects projects, _, err := git.Projects.ListProjects(&gitlab.ListProjectsOptions{}) if err != nil { panic(err) } for _, project := range projects { fmt.Printf("Project: %s\n", project.Name) } } ``` ### Ruby ```ruby require 'gitlab' # Initialize client Gitlab.configure do |config| config.endpoint = 'https://gitlab.com/api/v4' config.private_token = 'your_token' end # List projects projects = Gitlab.projects projects.each do |project| puts "Project: #{project.name}" end ``` ## Troubleshooting ### Common Authentication Issues **1. 401 Unauthorized** - Verify token is valid and not expired - Check token has required scopes - Ensure token is included in request headers **2. 403 Forbidden** - Check user permissions on resource - Verify token scope includes required access - For protected resources, check branch protection rules **3. SSH Connection Failed** - Verify SSH key is added to GitLab - Check SSH agent is running - Test connection: `ssh -T git@gitlab.com` - Verify SSH key permissions (600 for private key) **4. Token Not Working with 2FA** - Use personal access token instead of password - Or use SSH keys for Git operations **5. Deploy Token Issues** - Verify token hasn't expired - Check token scopes match operation - Ensure token is enabled in project settings ## Additional Resources - Personal Access Tokens: https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html - OAuth 2.0: https://docs.gitlab.com/ee/api/oauth2.html - SSH Keys: https://docs.gitlab.com/ee/user/ssh.html - Deploy Keys: https://docs.gitlab.com/ee/user/project/deploy_keys/ - Deploy Tokens: https://docs.gitlab.com/ee/user/project/deploy_tokens/