Rija Development: Using OAuth Tokens to Make REST API Calls
In my last Rija development post I talked about getting an OAuth access token for Jira so other people can use Rija. This post covers using the access token to make calls to Jira’s REST API. You must perform the following tasks to make API calls with an OAuth token:
- Get the user’s Jira cloud ID
- Get the URL for Jira’s REST APIs
- Add the access token to the authorization header
Get User’s Cloud ID
Each Jira site has a unique cloud ID. You can’t make calls to Jira’s REST API with an OAuth token without the cloud ID for the user’s Jira site. The first thing you must do is get the cloud ID. To get the cloud ID, make a URL request to the following URL:
https://api.atlassian.com/oauth/token/accessible-resources
Add the access token string to the authorization header. Run a URL session with the URL request. The following code retrieves a Jira cloud ID:
func retrieveCloudID() async -> String {
// Build the URL
var components = URLComponents()
components.scheme = "https"
components.host = "api.atlassian.com"
components.path = "/oauth/token/accessible-resources"
var request = URLRequest(url: components.url!)
guard let accessToken = getAccessToken() else {
return ""
}
// Add the access token to the authorization header
let authString = String("Bearer \(accessToken)")
request.addValue(authString, forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
// Retrieve the cloud ID
do {
let (data, error) = try await URLSession.shared.data(
for: request, delegate: nil)
let decoder = JSONDecoder()
let cloudDictionary = try decoder.decode([JiraCloudID].self,
from: data)
return cloudDictionary.first?.id ?? ""
} catch {
print(error)
return ""
}
}
JiraCloudID
is a struct I created with the properties id
, name
, and url
. The id
property contains the cloud ID.
Get Jira’s REST API URL
Jira has a different URL for making API calls with an OAuth access token than they have for making calls with a personal access token. The base URL is the following:
https://api.atlassian.com/ex/jira
Append the cloud ID and the path to the REST API call you’re making.
Add the Access Token to the Authorization Header
I showed the code to add the access token in the code to retrieve the cloud ID. But let’s show it again.
guard let accessToken = getAccessToken() else {
return ""
}
let authString = String("Bearer \(accessToken)")
request.addValue(authString, forHTTPHeaderField: "Authorization")
Jira’s REST API requires the string Bearer
followed by the access token string. Add the string to the URL request’s authorization header.
If you read Apple’s documentation for the URLRequest
class, they tell you not to set the Authorization header manually because it’s a reserved header. But Apple provides no alternative to manually setting the header manually so I have to set the Authorization header manually.
An Example API Call
The following code fetches someone’s Jira projects:
func fetchProjects() async throws -> JiraProjectList {
let cloudID = await getCloudID()
// Build the URL
var components = URLComponents()
components.scheme = "https"
components.host = "api.atlassian.com"
components.path = "/ex/jira/" + cloudID
+ "/rest/api/3/project/search"
// Sort projects alphabetically by default
components.queryItems = [
URLQueryItem(name: "orderBy", value: "name")
]
var request = URLRequest(url: components.url!)
// JiraProjectList contains an array of projects.
guard let accessToken = getAccessToken() else {
return JiraProjectList()
}
// Add access token to authorization.
let authString = String("Bearer \(accessToken)")
request.addValue(authString, forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let (data, error) = try await URLSession.shared.data(for:
request, delegate: nil)
let decoder = JSONDecoder()
return try decoder.decode(JiraProjectList.self, from: data)
}
I start by building the URL. I want to sort the projects alphabetically so I supply a URL query item. Then I add the access token to the authorization header. Finally I run the URL request.
Jira’s REST API returns the projects in a dictionary instead of an array. I have to create a JiraProjectList
struct to decode the JSON properly. All the struct contains is an array of projects.
About Rija
Rija is a Jira issue tracker under development for Mac (and possibly iOS). The following article provides more details on Rija: