tech
How to Generate GitLab Personal Access Tokens and API Keys
1253 words7 min read
- Authors

- Name
- Wan Ilhami
- @wan-ilhami-43515a184
In this guide, I'll show you how to create GitLab personal access tokens, configure deploy keys, and use them for API authentication and CI/CD pipelines.
I needed GitLab tokens for automating deployments, accessing the GitLab API, and integrating with third-party services for my DevOps pipeline.
First Approach (Personal Access Token)
Step 1: Access Token Settings
- Log in to your GitLab account
- Click your profile picture in the top right
- Select Preferences
- In the left sidebar, click Access Tokens
Step 2: Create New Token
- Click Add new token
- Enter a token name (e.g., "API Integration")
- Set expiration date (optional, for security choose 90 days)
- Select scopes based on your needs:
api- Full API accessread_user- Read user informationread_api- Read API accessread_registry- Read container registrywrite_repository- Push to repositoriesmaintainer_access- Maintain projects
- Click Create personal access token
Step 3: Copy Your Token
- Important: Copy your token immediately
- GitLab won't show it again after you leave the page
- Store it securely in environment variables or password manager
Step 4: Use Token for API Requests
- Add token to API requests as a header:
curl --header "PRIVATE-TOKEN: YOUR_GITLAB_TOKEN" \
https://gitlab.com/api/v4/user
- Or as a query parameter:
curl "https://gitlab.com/api/v4/user?private_token=YOUR_GITLAB_TOKEN"
- In JavaScript:
const token = process.env.GITLAB_TOKEN;
const response = await fetch('https://gitlab.com/api/v4/user', {
headers: {
'PRIVATE-TOKEN': token
}
});
const data = await response.json();
console.log(data);
Step 5: Use Token for Git Operations
- Clone private repositories:
git clone https://oauth2:YOUR_GITLAB_TOKEN@gitlab.com/username/repo.git
- Configure Git to use token:
git config --global credential.helper store
echo "https://oauth2:YOUR_GITLAB_TOKEN@gitlab.com" > ~/.git-credentials
Second Approach (OAuth Application)
Step 1: Create OAuth Application
- Go to Admin Area (visible if you have admin access)
- Select Applications under System
- Click New application
- Fill in the application details:
- Name: Your app name
- Redirect URI:
https://yourapp.com/callback - Scopes: Select required scopes
- Check Trusted if this is your own application
- Click Save application
Step 2: Get Credentials
- You'll receive:
- Application ID
- Secret
- Store both securely in environment variables
Step 3: Create Authorization URL
- Build the authorization URL:
https://gitlab.com/oauth/authorize?client_id=$APPLICATION_ID&redirect_uri=$REDIRECT_URI&response_type=code&scope=$SCOPE&state=$STATE
- Example:
https://gitlab.com/oauth/authorize?client_id=abc123&redirect_uri=https%3A%2F%2Fyourapp.com%2Fcallback&response_type=code&scope=read_user&state=random_state
Note: URL encode your redirect URI
Step 4: Exchange Code for Token
- When users authorize, they're redirected with a
codeparameter - Exchange it for an access token:
curl --request POST https://gitlab.com/oauth/token \
-d "client_id=$APPLICATION_ID" \
-d "client_secret=$SECRET" \
-d "code=$CODE" \
-d "grant_type=authorization_code" \
-d "redirect_uri=$REDIRECT_URI"
Step 5: Handle Token Response
- Response includes:
{
"access_token": "de6780bc506a0446529482c321cdf285",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "8257e65c97f3a53ce93caf05cb0",
"created_at": 1622548961
}
- Use
access_tokenfor API requests - Store
refresh_tokenfor token renewal
Third Approach (Deploy Keys)
Step 1: Generate SSH Key Pair
ssh-keygen -t rsa -b 4096 -C "deploy@yourapp.com" -f deploy_key
Step 2: Add Deploy Key to Project
- Go to your GitLab project
- Select Settings > Repository
- Expand Deploy keys
- Click Add deploy key
- Enter key title (e.g., "CI/CD Deploy Key")
- Paste your public key (from
deploy_key.pub) - Check Grant write permissions to this key if needed
- Click Add key
Step 3: Use Deploy Key in CI/CD
- Add to your
.gitlab-ci.yml:
deploy:
stage: deploy
before_script:
- mkdir -p ~/.ssh
- ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts
- echo "$DEPLOY_KEY" | tr -d '\r' | ssh-add - > /dev/null
script:
- git clone git@gitlab.com:username/repo.git
- cd repo && ./deploy.sh
only:
- main
- Add private key as CI/CD variable: Settings > CI/CD > Variables
- Name:
DEPLOY_KEY, Value: contents ofdeploy_key
API Request Examples
Get Current User
curl --header "PRIVATE-TOKEN: YOUR_TOKEN" \
https://gitlab.com/api/v4/user
List Projects
curl --header "PRIVATE-TOKEN: YOUR_TOKEN" \
https://gitlab.com/api/v4/projects?per_page=10
Create Issue
curl --request POST --header "PRIVATE-TOKEN: YOUR_TOKEN" \
--data "title=New%20issue&description=Test" \
https://gitlab.com/api/v4/projects/1/issues
Trigger Pipeline
curl --request POST --header "PRIVATE-TOKEN: YOUR_TOKEN" \
https://gitlab.com/api/v4/projects/1/pipeline?ref=main
Get Repository Files
curl --header "PRIVATE-TOKEN: YOUR_TOKEN" \
https://gitlab.com/api/v4/projects/1/repository/tree
Python Implementation Example
import os
import requests
from dotenv import load_dotenv
load_dotenv()
GITLAB_URL = 'https://gitlab.com'
GITLAB_TOKEN = os.getenv('GITLAB_TOKEN')
PROJECT_ID = os.getenv('GITLAB_PROJECT_ID')
headers = {
'PRIVATE-TOKEN': GITLAB_TOKEN,
'Content-Type': 'application/json'
}
def get_project_info():
"""Get project details"""
response = requests.get(
f'{GITLAB_URL}/api/v4/projects/{PROJECT_ID}',
headers=headers
)
return response.json()
def create_issue(title, description):
"""Create a new issue"""
data = {
'title': title,
'description': description
}
response = requests.post(
f'{GITLAB_URL}/api/v4/projects/{PROJECT_ID}/issues',
headers=headers,
json=data
)
return response.json()
def list_pipelines():
"""List recent pipelines"""
response = requests.get(
f'{GITLAB_URL}/api/v4/projects/{PROJECT_ID}/pipelines',
headers=headers
)
return response.json()
def trigger_pipeline(ref='main'):
"""Trigger a pipeline on specified branch"""
data = {'ref': ref}
response = requests.post(
f'{GITLAB_URL}/api/v4/projects/{PROJECT_ID}/pipeline',
headers=headers,
json=data
)
return response.json()
if __name__ == '__main__':
print("Project:", get_project_info()['name'])
new_issue = create_issue('Test Issue', 'This is a test')
print("Created issue:", new_issue['id'])
print("Pipelines:", list_pipelines())
Node.js Implementation Example
require('dotenv').config();
const axios = require('axios');
const GITLAB_URL = 'https://gitlab.com';
const GITLAB_TOKEN = process.env.GITLAB_TOKEN;
const PROJECT_ID = process.env.GITLAB_PROJECT_ID;
const client = axios.create({
baseURL: `${GITLAB_URL}/api/v4`,
headers: {
'PRIVATE-TOKEN': GITLAB_TOKEN
}
});
async function getProjectInfo() {
try {
const response = await client.get(`/projects/${PROJECT_ID}`);
return response.data;
} catch (error) {
console.error('Error:', error.response.data);
}
}
async function createIssue(title, description) {
try {
const response = await client.post(
`/projects/${PROJECT_ID}/issues`,
{ title, description }
);
return response.data;
} catch (error) {
console.error('Error:', error.response.data);
}
}
async function listPipelines() {
try {
const response = await client.get(`/projects/${PROJECT_ID}/pipelines`);
return response.data;
} catch (error) {
console.error('Error:', error.response.data);
}
}
async function triggerPipeline(ref = 'main') {
try {
const response = await client.post(
`/projects/${PROJECT_ID}/pipeline`,
{ ref }
);
return response.data;
} catch (error) {
console.error('Error:', error.response.data);
}
}
module.exports = { getProjectInfo, createIssue, listPipelines, triggerPipeline };
GitLab CI/CD Token Example
Add this to .gitlab-ci.yml to use tokens in pipelines:
stages:
- build
- deploy
variables:
REGISTRY_URL: "registry.gitlab.com"
CI_REGISTRY_USER: "oauth2"
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $REGISTRY_URL
- docker build -t $REGISTRY_URL/$CI_PROJECT_PATH:latest .
- docker push $REGISTRY_URL/$CI_PROJECT_PATH:latest
only:
- main
deploy:
stage: deploy
image: alpine:latest
script:
- echo "Deploying to production..."
- curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
https://gitlab.com/api/v4/projects/$CI_PROJECT_ID
only:
- main
Security Best Practices
- Never commit tokens to repositories - use CI/CD variables
- Rotate tokens regularly - regenerate quarterly
- Use limited scopes - only grant necessary permissions
- Enable two-factor authentication - protect your account
- Revoke unused tokens - regularly audit and clean up
- Use deploy keys for read-only repository access
- Store secrets in CI/CD variables - not in code or
.envfiles - Monitor token usage - check activity logs for unusual access
- Implement expiration dates - shorter expiry improves security
- Check GitLab Token Security
Troubleshooting
| Issue | Solution |
|---|---|
| "401 Unauthorized" | Verify token is correct and not expired |
| Token not working in CI/CD | Add as CI/CD variable, not hardcoded |
| Deploy key permission denied | Ensure key has write access if needed |
| Token scope insufficient | Create new token with broader scope |
| Lost token | Revoke old token, create new one |
Ready to integrate? Check out the GitLab API Documentation and GitLab CI/CD Documentation for complete reference.