-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Implement OAuth1 authorization method #2989
base: main
Are you sure you want to change the base?
Conversation
f4f0392
to
3499321
Compare
96650ba
to
6c272bc
Compare
cd12fb9
to
9b4a1b1
Compare
a5cb10d
to
e1ea8c0
Compare
e1ea8c0
to
87a4aea
Compare
87a4aea
to
9edd229
Compare
9edd229
to
d7e5cdb
Compare
Time to go read the OAuth 1.0(and rev A) spec. |
@pietrygamat mind sharing the details on what you are using to test it in local? |
I used the example oauth1 server as a docker container: https://github.com/BeryJu/oauth1-test-server |
} | ||
const authHeader = oauth.toHeader(oauth.authorize(accessTokenRequestData, signingToken)); | ||
console.log("Requesting Access Token from", accessTokenRequestData.url); | ||
const accessTokenResponse = await axios.post(accessTokenRequestData.url, {},{ headers: authHeader }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO 1: we need to send a separate request to access token url. This implementation creates a basic axios.post, but more complete solution should preconfigure the request according to global / collection settings (mTLS, proxy config). Possibly out of scope for this PR, but should be addressed if this is to be merged.
TODO 2: Some APIs may expect such request to include specific cookies or headers, and so there should be a way for the user to add additional headers and/or additional request parameters. Bruno faces this problem with OAuth2, like explained here, and the same issue may very well be present in OAuth1. It may be considered lower priority.
// https://oauth.net/core/1.0a/#anchor13 | ||
// 9.1.1. Normalize Request Parameters | ||
const isPostWithUrlEncodedFormData = (request) => { | ||
return request.headers['content-type'] === 'application/x-www-form-urlencoded' && request.method === 'POST'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly outside of this PR's scope, but there should be a more generic way of reading well-known headers (content-type
here, authorization
few lines below, etc) within the code base that avoids pitfalls related to case-sensitive string comparison. Note, content-type
may have been set by a user script as e.g. Content-Type
.
Or maybe there already is a better way?
window.on('ready-to-show', () => window.show()); | ||
window.webContents.on('certificate-error', (event, url, error, certificate, callback) => { | ||
event.preventDefault(); | ||
callback(!preferencesUtil.shouldVerifyTls()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can honor No TLS verification
setting like this, but this should also work with custom CA and proxy settings configured in Bruno. This is the same problem as there is with OAuth2 flow, so I guess it's outside of scope for now?
const relativeFile = (file) => { | ||
if (file) { | ||
if (isWindowsOS()) { | ||
return slash((path.win32.relative(collection.pathname, file))); | ||
} else { | ||
return path.posix.relative(collection.pathname, file); | ||
} | ||
} else { | ||
return ''; | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may be outdated method of getting relative path to a local file with recent changes to file picker, not sure.
@@ -0,0 +1,79 @@ | |||
const inputsConfig = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some of these inputs are required to fill (consumer key/secret), and some will be filled by Bruno during execution if found empty (verifier, access token). Some will only make sense under certain conditions (rsa-private key is only needed when using RSA signing method, but then it's mandatory).
The UX improvements like hints or auto-disabling controls depending on other choices may be introduced in the future, but I guess it's better left out of this PR.
Description
This pull request aims to add OAuth1.0a as supported authorization mode to Bruno.
resolves: #1004
The OAuth1 flow as defined in https://oauth.net/core/1.0a consists of two distinct stages (and more substages):
Step 2, while not exactly trivial, can be accomplished by scripting, but what I think is really important for API client like Bruno, is the ability to assist user in Step 1- actually obtaining the token.
The approach currently used for OAuth2 Authorization Code flow is a great example of how the solution could look like.
Implementation details
When OAuth1 authorization is used for request, the Authorization header is evaluated using oauth-1.0a library and included in the request during execution, based on the following parameters:
In case user does not yet have Access Token, they must provide the following information about API they want to access:
And then also:
Then, during request execution Bruno will make additional requests, and will open the browser window to allow user sign-in with the external provider and ask for permission.
Demo
Screencast.from.2024-09-02.21-41-41.mp4
Todos
This flow should support several variations, including
HMAC_SHA*
- works with real servicesRSA_SHA*
- using external private key - should workPLAINTEXT
- should workAuthorization Header
Form-Encoded Body
Request Query Parameters
Some additional considerations:
Contribution Checklist: