Open clocklear opened 8 months ago
For people that found this page via searching the issue, this is now possible with a little workaround in v1.11.0. Set the collection level auth as OAuth 2.0 (like Insomnia/Postman) Navigate to the "Script" pane of the collection and set the access token as a variable in the "Post response" section
var token = res.body.access_token;
if (token) {
bru.setVar('oauth2_token', token)
}
Then navigate to the "Headers" pane still in the collection settings and set the "Authorization" header as needed. i.e.
Once you do this, you only need to "Get the token" once and then all requests in the collection will use this access token.
Full collection.bru for anything that just wants to copy that.
headers {
Authorization: Bearer {{oauth2_token}}
}
auth {
mode: oauth2
}
auth:oauth2 {
grant_type: authorization_code
callback_url: {{RedirectUrl}}
authorization_url: {{AuthorizationUrl}}
access_token_url: {{AccessTokenUrl}}
client_id: {{ClientId}}
client_secret:
scope: {{GatewayScope}}
pkce: false
}
script:post-response {
var token = res.body.access_token;
if (token) {
bru.setVar('oauth2_token', token)
}
}
DO NOT change the request level settings (auth or script), leave the request level Auth settings on "No Auth"
After setting this up, you would just need to navigate to the "Auth" pane in collection settings, press "Get New Token" and you should be good to go to call the protected endpoints in the collection.
@jackj93 this isn't working for me either (v 1.12.1 now). Var isn't being set by the script either when hitting "Get Access Token" button on the Collection Authorization or in making a call that uses inherit authorization.
@jackj93 did you have to install an external module for this to work? When putting the code you mention in the pre request script location on the collection, I just get this error:
Error invoking remote method 'send-http-request': ReferenceError: res is not defined
Any idea?
@jackj93 this isn't working for me either (v 1.12.1 now). Var isn't being set by the script either when hitting "Get Access Token" button on the Collection Authorization or in making a call that uses inherit authorization.
In the request themselves you have to set the "No Auth"
@jackj93 did you have to install an external module for this to work? When putting the code you mention in the pre request script location on the collection, I just get this error:
Error invoking remote method 'send-http-request': ReferenceError: res is not defined
Any idea?
All the configuration I listed go in the configuration for the collection. do NOT put anything in the request settings The script is meant to be put in the "Post Response", sorry if that part wasn't clear
Thank you @jackj93, it works now! Retrospectively I should've seen in the code that it was going in the post response part.
Update: As of v1.11.0 I see that OAuth2 is supported at the collection level, but setting auth to 'inherit' at the request level isn't supported:
Using @jackj93 's scripting provides a workaround: we can save the collection token as a variable and use that in requests in the appropriate place (for me, I set an Authorization
header with the value Bearer {{oauth2_token}}
). Is inherit
going to be supported natively in the future without scripting hacks?
In addition to the Post Request script by @jackj93, I'm using this Pre Request script on Collection level, then you don't need to add the header manually on each request:
var token = bru.getVar('oauth2_token')
if (token) {
req.setHeader('Authorization', `Bearer ${token}`)
}
Is there a way to reuse a token across multiple collections?
I have many collections but they use the same OAuth provider. So now I have to get a token for each collection individually, instead of doing it once and reusing it in all collections.
I guess a workaround would be to have only one collection per OAuth provider and group the requests in folders and subfolders.
Workarounds aside (which work, thanks for that) is there intention to work on this formally? Debating the pros and cons of waiting on this to be solved upstream and permit inheritance on the collection requests when using Oauth2 instead of injecting a pre-script one every single request.
Thanks
I am taking approach the insomnia way for this
created a request responsible for just fetching the token and storing the variable in post response
then using the variable in header.
Only friction with this approach is we have to fetch token manually once before using any of the api in our collection.
insomnia saves a little time in this by allowing us to directly use the attribute from some other response. Also it can auto refresh, hoping to see similar feature in bruno as well :)
Just a suggestion: until such time that the header can be added automatically for OAuth, perhaps this message could point people to this thread:
It took me 20 mins to track this down.
After applying @jackj93's workaround (thanks for that) requests are fine, however, when attempting to get a new token I'm getting invalid_client
errors. I tracked this down to the Authorization
header being added, and disabling it allows a new token to be generated. Has anyone had this issue, and possibly got a better way to handle it than manually toggling the header value?
The work arounds suggested still seem to require manually clicking the "Get Access Token" on the collection every time the token expires. This isn't great for api's that use short lived tokens. Luckily the client credential flow can be automated fairly simply by adding the following Pre Request script on the collection:
const axios = require('axios');
let token = bru.getEnvVar('access_token_set_by_collection_script');
let tokenExpiration = bru.getEnvVar('access_token_expiration');
let currentTime = (new Date()).getTime();
if (!token || !tokenExpiration || tokenExpiration < currentTime) {
try {
console.log("requesting new token");
const tokenData = (await axios.post(
bru.getEnvVar('AccessTokenUrl'),
{
client_id: bru.getEnvVar('ClientId'),
client_secret: bru.getEnvVar('ClientSecret'),
grant_type: 'client_credentials'
},
{
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
}
)).data;
let now = new Date();
let expiration = (now.setSeconds(now.getSeconds() + tokenData.expires_in - 60)); //Add a minute buffer to expiration time.
bru.setEnvVar('access_token_set_by_collection_script', tokenData.access_token);
bru.setEnvVar('access_token_expiration', expiration);
} catch (error) {
console.log(error);
}
} else {
console.log("using existing token");
}
req.setHeader('Authorization', `Bearer ${bru.getEnvVar('access_token_set_by_collection_script')}`)
This stores the access token and token expiration time in environment variables and checks each request to see if a new token needs to be retrieved. It would be really helpful if the bruno Oauth2 documentation for client credentials provided an example like this to simplify the authentication process.
Since the majority of use-cases use the same scripts at this point, is there a reason why this functionality isn't baked into the client?
I tried it in another way.
Place below script in post response under collection setting
if(req.getAuthMode() == 'oauth2' && res.body.access_token) { bru.setVar('access_token_set_by_collection_script', res.body.access_token); }
Then go to your request and change the Auth setting to Bearer Token and place below code
{{access_token_set_by_collection_script}}
When configuring OAuth 2.0, it would be helpful to configure once per collection instead of requiring configuration on individual requests:
Auth configuration at the request level:
Auth configuration at the collection level:
(This is for Bruno v1.10.0)