A TypeScript client for interacting with the Jira API
npm install jira-api-clientbash
npm install jira-api-client
`
Authentication
This client supports two authentication methods for Jira:
$3
Bearer token authentication is the recommended approach for security reasons. It uses a personal access token that you can generate from your Atlassian account.
To generate a token:
1. Log in to https://id.atlassian.com/manage-profile/security/api-tokens
2. Click "Create API token"
3. Give your token a name and click "Create"
4. Copy the token value (you won't be able to see it again)
$3
Basic authentication uses your email and API token (as password). This method is supported for backward compatibility but is less secure than Bearer token authentication.
Note: Never use your actual Atlassian account password. Always use an API token as the password.
Configuration
You can configure the client using environment variables or by passing a configuration object directly.
$3
Create a .env file in your project root:
`
Required
JIRA_BASE_URL=https://your-domain.atlassian.net
JIRA_TOKEN=your-bearer-token
For Basic authentication (optional)
JIRA_EMAIL=your-email@example.com
Optional Configuration
JIRA_API_VERSION=3
JIRA_REQUEST_TIMEOUT=30000
`
Then initialize the client:
`typescript
import { JiraClient } from 'jira-api-client';
const jira = JiraClient.fromEnv();
`
$3
`typescript
import { JiraClient } from 'jira-api-client';
// Bearer token authentication (recommended)
const jira = new JiraClient({
baseUrl: 'https://your-domain.atlassian.net',
token: 'your-bearer-token',
apiVersion: 3, // optional, defaults to 3
timeout: 30000, // optional, defaults to 30000 (30 seconds)
});
// OR Basic authentication with email/password
const jiraBasic = new JiraClient({
baseUrl: 'https://your-domain.atlassian.net',
email: 'your-email@example.com',
token: 'your-api-token', // In this case, token is used as password
apiVersion: 3, // optional, defaults to 3
timeout: 30000, // optional, defaults to 30000 (30 seconds)
});
`
The client automatically detects which authentication method to use based on whether you provide an email:
- If email is provided, Basic authentication is used
- If only token is provided, Bearer token authentication is used
$3
1. Token Storage: Never hardcode your authentication tokens in your source code. Use environment variables or a secure secrets management system.
2. Token Permissions: When creating API tokens, follow the principle of least privilege. Only grant the permissions that are necessary for your application to function.
3. Token Rotation: Regularly rotate your API tokens, especially in production environments.
4. HTTPS: Always use HTTPS when communicating with the Jira API to ensure your authentication credentials are encrypted during transmission.
Usage Examples
$3
`typescript
import { JiraClient, CreateIssueData } from 'jira-api-client';
const jira = JiraClient.fromEnv();
// Get an issue
const issue = await jira.issues.getIssue('PROJECT-123');
console.log(issue.fields.summary);
// Create an issue
const newIssueData: CreateIssueData = {
fields: {
project: { key: 'PROJECT' },
summary: 'New issue created via API',
description: 'This is a description of the issue',
issuetype: { name: 'Task' },
},
};
const newIssue = await jira.issues.createIssue(newIssueData);
console.log(Created issue: ${newIssue.key});
// Update an issue
await jira.issues.updateIssue('PROJECT-123', {
fields: {
summary: 'Updated summary',
description: 'Updated description',
},
});
// Delete an issue
await jira.issues.deleteIssue('PROJECT-123');
// Search for issues using JQL
const searchResults = await jira.issues.searchIssues(
'project = PROJECT AND status = "In Progress"'
);
console.log(Found ${searchResults.total} issues);
`
$3
`typescript
// Get comments for an issue
const comments = await jira.issues.getComments('PROJECT-123');
console.log(Issue has ${comments.total} comments);
// Add a comment
const comment = await jira.issues.addComment('PROJECT-123', 'This is a new comment');
console.log(Added comment with ID: ${comment.id});
// Update a comment
await jira.issues.updateComment('PROJECT-123', comment.id, 'Updated comment text');
// Delete a comment
await jira.issues.deleteComment('PROJECT-123', comment.id);
`
$3
`typescript
// Get available transitions
const transitions = await jira.issues.getTransitions('PROJECT-123');
console.log('Available transitions:', transitions.map(t => t.name));
// Transition an issue
await jira.issues.transitionIssue('PROJECT-123', 'Done');
`
$3
`typescript
// Get all projects
const projects = await jira.projects.getAllProjects();
console.log(Found ${projects.values.length} projects);
// Get a specific project
const project = await jira.projects.getProject('PROJECT');
console.log(Project name: ${project.name});
// Get project issue types
const issueTypes = await jira.projects.getProjectIssueTypes('PROJECT');
console.log('Issue types:', issueTypes.map(t => t.name));
// Search for projects
const searchResults = await jira.projects.searchProjects('Marketing');
console.log(Found ${searchResults.values.length} matching projects);
`
$3
`typescript
// Get current user
const currentUser = await jira.users.getCurrentUser();
console.log(Current user: ${currentUser.displayName});
// Search for users
const users = await jira.users.searchUsers('john');
console.log(Found ${users.values.length} matching users);
// Get assignable users for a project
const assignableUsers = await jira.users.getAssignableUsers('PROJECT');
console.log(Found ${assignableUsers.values.length} assignable users);
`
$3
`typescript
import { fetchAllPages } from 'jira-api-client';
// Fetch all issues across multiple pages
const allIssues = await fetchAllPages(
params => jira.issues.searchIssues('project = PROJECT', undefined, params)
);
console.log(Fetched all ${allIssues.length} issues);
// Or manually handle pagination
let startAt = 0;
const maxResults = 50;
let isLast = false;
while (!isLast) {
const response = await jira.issues.searchIssues(
'project = PROJECT',
undefined,
{ startAt, maxResults }
);
// Process the current page of results
response.values.forEach(issue => {
console.log(issue.key, issue.fields.summary);
});
isLast = response.isLast;
startAt += maxResults;
}
`
$3
`typescript
import { isJiraError } from 'jira-api-client';
try {
await jira.issues.getIssue('NONEXISTENT-123');
} catch (error) {
if (isJiraError(error)) {
console.error(Jira API Error (${error.status}):, error.message);
console.error('Error details:', error.errors);
console.error('Error messages:', error.errorMessages);
} else {
console.error('Unknown error:', error);
}
}
`
API Documentation
$3
The main client class that provides access to all API endpoints.
`typescript
class JiraClient {
readonly issues: IssuesApiClient;
readonly projects: ProjectsApiClient;
readonly users: UsersApiClient;
constructor(config: JiraClientConfig);
static fromEnv(): JiraClient;
}
`
$3
`typescript
class IssuesApiClient {
getIssue(issueIdOrKey: string, fields?: string[]): Promise;
createIssue(data: CreateIssueData): Promise;
updateIssue(issueIdOrKey: string, data: UpdateIssueData): Promise;
deleteIssue(issueIdOrKey: string, deleteSubtasks?: boolean): Promise;
searchIssues(jql: string, fields?: string[], pagination?: PaginationParams): Promise>;
getTransitions(issueIdOrKey: string): Promise;
transitionIssue(issueIdOrKey: string, transitionIdOrName: string): Promise;
getComments(issueIdOrKey: string, pagination?: PaginationParams): Promise>;
addComment(issueIdOrKey: string, body: string): Promise;
updateComment(issueIdOrKey: string, commentId: string, body: string): Promise;
deleteComment(issueIdOrKey: string, commentId: string): Promise;
assignIssue(issueIdOrKey: string, accountId: string | null): Promise;
}
`
$3
`typescript
class ProjectsApiClient {
getAllProjects(pagination?: PaginationParams): Promise>;
getProject(projectIdOrKey: string): Promise;
getProjectIssueTypes(projectIdOrKey: string): Promise;
getProjectComponents(projectIdOrKey: string): Promise;
getProjectVersions(projectIdOrKey: string): Promise;
getProjectStatuses(projectIdOrKey: string): Promise;
searchProjects(query: string, pagination?: PaginationParams): Promise>;
}
`
$3
`typescript
class UsersApiClient {
getCurrentUser(): Promise;
getUser(accountId: string): Promise;
searchUsers(query: string, pagination?: PaginationParams): Promise>;
getAssignableUsers(projectIdOrKey: string, pagination?: PaginationParams): Promise>;
}
`
Changelog
See the CHANGELOG.md file for details on all changes and releases.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
1. Fork the repository
2. Create your feature branch (git checkout -b feature/amazing-feature)
3. Commit your changes (git commit -m 'Add some amazing feature')
4. Push to the branch (git push origin feature/amazing-feature`)