feat: Enable OAuth 3LO support
Summary
fixes #863
This PR allows for users to have another option (oauth) when generating their JIRA config.yml for the Cloud installation.
Details
This PR implements JIRA's 3LO OAuth solution for users to obtain a JIRA access token.
Each consumer of jira-cli will need to create a JIRA App with the specific scopes in order to connect it properly with their JIRA cloud instance.
The oauth secret will be stored in the .config/.jira directory, where the tokens will be automatically regenerated when it expires and the newly generated tokens will be cached to the oauth secret file.
How to create a JIRA App properly:
See this discussion post here: https://github.com/ankitpokhrel/jira-cli/discussions/879#discussion-8604411
Known Limitations/Issues
[!NOTE]
This limitation has also been noted in the README under theKnown Issuessection.
Ideally, for OAuth, we would have one single distributed app that can be installed in multiple different JIRA cloud instances. However, The 3LO doesn't support Proof Key for Code Exchange (PKCE). Without this support, we would have to share the single distrubuted app's client secret with all the consumers. See these links for more info:
- https://jira.atlassian.com/browse/ECO-283
- https://community.developer.atlassian.com/t/oauth-2-0-with-proof-key-for-code-exchange-pkce/80173/3
As noted in the forum above, a workaround would be that each consumer has to create their own JIRA app and use that app's client ID and secret in the jira-cli client app.
- This basically acts like a proxy to funnel requests into your JIRA cloud instance
Testing Done
make deps install=> WORKS~/go/bin/jira issue create -tTask -s"TEST TICKET" -l"testing" --template ~/jira/task.tmpl -a$(~/go/bin/jira me)=> WORKS (created a ticket, and proper link)make test=> WORKSmake lint=> WORKSmake ci=> WORKS
cc: @ankitpokhrel for visibility. It'll be great if this can be reviewed/merged soon, so folks that can only authenticate through OAuth 3LO can start using this tool again.
@ankitpokhrel Could you take a look at this PR when you get a chance? I think this is a nice feature add (and personally been using it for months now without hiccup)
@christianarty Thanks for the PR! I'm currently away, I'll look into this in a few weeks.
@ankitpokhrel Hey! Just wanted to see if you had a moment to take a peek at this PR! Would be appreciated thanks!
Also added a new commit that expanded the default scopes since recently realized, with the oauth, for jira sprint list to work properly needed extra scopes: https://developer.atlassian.com/cloud/jira/software/rest/api-group-board/#api-rest-agile-1-0-board-boardid-sprint-sprintid-issue-get
https://developer.atlassian.com/cloud/jira/software/rest/api-group-sprint/#api-rest-agile-1-0-sprint-sprintid-issue-post
I have a suggestion here.
I played with the app and 3LO.
It works great except when the app you created doesn't have the expected scope
I feel like the CLI should display the scope it expect in the console. Either by default, or when the timeout happens.
The error message on the consent screen provided by Jira is unclear.
Also, I'm unsure if you can report the scope the app was created with without being authenticated, but it would be great to double check what us expected and what is currently on the created oauth app
I have a suggestion here.
I played with the app and 3LO.
It works great except when the app you created doesn't have the expected scope
I feel like the CLI should display the scope it expect in the console. Either by default, or when the timeout happens.
The error message on the consent screen provided by Jira is unclear.
Also, I'm unsure if you can report the scope the app was created with without being authenticated, but it would be great to double check what us expected and what is currently on the created oauth app
@ccoVeille Great suggestion! I am not sure about the scope when unauthorized and I think that should be a separate PR (this PR is already big enough tbh), but I did just add for the CLI to print out the expected scopes when creating a new config. It looks like this:
Do you think it should look like that or another format?
EDIT: I removed the offline_access scope from printing to console since that is a special scope you don't have to click on JIRA ui.
@ankitpokhrel I was **just a bit off ** when I said a couple days I'll fix it 😅 but I refactored this to use the keyring storage as the primary and file system as secondary and it works as expected. Also wrote some tests to account for it but I think this would suffice. I also updated the README to account for some of the changes I did with the env vars.
I have a suggestion here.
I played with the app and 3LO.
It works great except when the app you created doesn't have the expected scope
I feel like the CLI should display the scope it expect in the console. Either by default, or when the timeout happens.
The error message on the consent screen provided by Jira is unclear.
Also, I'm unsure if you can report the scope the app was created with without being authenticated, but it would be great to double check what us expected and what is currently on the created oauth app
@ccoVeille Great suggestion! I am not sure about the scope when unauthorized and I think that should be a separate PR (this PR is already big enough tbh), but I did just add for the CLI to print out the expected scopes when creating a new config. It looks like this:
Do you think it should look like that or another format?
I think it's good, except they should be ordered alphabetically, or in the order they can be found in Jira developer console
Also, I'm unsure if you can report the scope the app was created with without being authenticated, but it would be great to double check what us expected and what is currently on the created oauth app
Great suggestion! I am not sure about the scope when unauthorized and I think that should be a separate PR (this PR is already big enough tbh)
Yes, it does. And as we both said, we are not sure it can be done.
Thanks @ccoVeille for the comments! Appreciate the extra look! I've addressed them all and tested it with the new revisions and things work as intended. @ankitpokhrel it now defaults to the keyring and fallsback to the filesystem storage. Please let me know if there is anything else we need to do in this PR otherwise i think its ready to 🚢
Also, @ccoVeille these are what the new order of expected scopes, alphabetically sorted and grouped by scope type.
Hoping to see this merged soon, looks great!
@ankitpokhrel, whenever you get a chance could you drop a 🚢 . Would be greatly appreciated thanks!