Skip to content

Commit

Permalink
feat: add API key authentication in CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
sanjaikumar-bruno committed Jan 15, 2025
1 parent d2d7638 commit e068efc
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 0 deletions.
37 changes: 37 additions & 0 deletions packages/bruno-cli/src/runner/prepare-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,25 @@ const prepareRequest = (item = {}, collection = {}) => {
if (collectionAuth.mode === 'bearer') {
axiosRequest.headers['Authorization'] = `Bearer ${get(collectionAuth, 'bearer.token')}`;
}

if (collectionAuth.mode === 'apikey'){
const placement = get(collectionAuth, "apikey.placement");
const key = get(collectionAuth, "apikey.key");
const value = get(collectionAuth, "apikey.value");

if (placement === 'header') {
axiosRequest.headers[key] = value;
} else if (placement === 'queryparams') {
try {
const urlObj = new URL(request.url);
urlObj.searchParams.set(key, value);
axiosRequest.url = urlObj.toString();
} catch (error) {
console.error('Invalid URL:', request.url, error);
}
}

}
}

if (request.auth) {
Expand Down Expand Up @@ -79,6 +98,24 @@ const prepareRequest = (item = {}, collection = {}) => {
if (request.auth.mode === 'bearer') {
axiosRequest.headers['Authorization'] = `Bearer ${get(request, 'auth.bearer.token')}`;
}

if (request.auth?.mode === 'apikey') {
const placement = get(request, "auth.apikey.placement");
const key = get(request, "auth.apikey.key");
const value = get(request, "auth.apikey.value");

if (placement === 'header') {
axiosRequest.headers[key] = value;
} else if (placement === 'queryparams') {
try {
const urlObj = new URL(request.url);
urlObj.searchParams.set(key, value);
axiosRequest.url = urlObj.toString();
} catch (error) {
console.error('Invalid URL:', request.url, error);
}
}
}

if (request.auth.mode === 'wsse') {
const username = get(request, 'auth.wsse.username', '');
Expand Down
113 changes: 113 additions & 0 deletions packages/bruno-cli/tests/runner/prepare-request.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,116 @@ describe('prepare-request: prepareRequest', () => {
});
});
});

describe('Properly maps inherited auth from collectionRoot', () => {
// Initialize Test Fixtures
let collectionRoot, request;

beforeEach(() => {
// Reset test fixtures
collectionRoot = {
request: {
auth: {}
}
};

request = {
url: 'https://www.usebruno.com',
auth: {
mode: "inherit"
},
body: {
mode: 'json',
json: '{\n"test": {{someVar}} // comment\n}'
}
};
});

it('If collection auth is apikey in header', () => {
collectionRoot.request.auth = {
mode: "apikey",
apikey: {
key: "x-api-key",
value: "{{apiKey}}",
placement: "header"
}
};

const result = prepareRequest(request, collectionRoot);
expect(result.headers).toHaveProperty('x-api-key', '{{apiKey}}');
});


it('If collection auth is apikey in header and request has existing headers', () => {
collectionRoot.request.auth = {
mode: "apikey",
apikey: {
key: "x-api-key",
value: "{{apiKey}}",
placement: "header"
}
};

request['headers'] = [{ name: 'Content-Type', value: 'application/json', enabled: true }];

const result = prepareRequest(request, collectionRoot);
expect(result.headers).toHaveProperty('Content-Type', 'application/json');
expect(result.headers).toHaveProperty('x-api-key', '{{apiKey}}');
});

it('If collection auth is apikey in query parameters', () => {
collectionRoot.request.auth = {
mode: "apikey",
apikey: {
key: "apiKey",
value: "{{apiKey}}",
placement: "queryparams"
}
};

const expected = `${request.url}?${collectionRoot.request.auth.apikey.key}=${collectionRoot.request.auth.apikey.value}`;
const result = prepareRequest(request, collectionRoot);
expect(result.url).toEqual(expected);
});

it('If collection auth is basic auth', () => {
collectionRoot.request.auth = {
mode: 'basic',
basic: {
username: 'testUser',
password: 'testPass123'
}
};

const result = prepareRequest(request, collectionRoot);
const expected = { username: 'testUser', password: 'testPass123' };
expect(result.auth).toEqual(expected);
});

it('If collection auth is bearer token', () => {
collectionRoot.request.auth = {
mode: 'bearer',
bearer: {
token: 'token'
}
};

const result = prepareRequest(request, collectionRoot);
expect(result.headers).toHaveProperty('Authorization', 'Bearer token');
});

it('If collection auth is bearer token and request has existing headers', () => {
collectionRoot.request.auth = {
mode: 'bearer',
bearer: {
token: 'token'
}
};

request['headers'] = [{ name: 'Content-Type', value: 'application/json', enabled: true }];

const result = prepareRequest(request, collectionRoot);
expect(result.headers).toHaveProperty('Authorization', 'Bearer token');
expect(result.headers).toHaveProperty('Content-Type', 'application/json');
});
});
28 changes: 28 additions & 0 deletions packages/bruno-tests/src/auth/apiKey.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const express = require('express');
const router = express.Router();

const VALID_API_KEY = 'my-secret-api-key';
const VALID_KEY_NAME = 'api-key';

const apiKeyAuthMiddleware = (req, res, next) => {
const apiKeyFromHeader = req.headers[VALID_KEY_NAME.toLowerCase()];
const apiKeyFromQuery = req.query[VALID_KEY_NAME];

const apiKey = apiKeyFromHeader || apiKeyFromQuery;

if (!apiKey) {
return res.status(401).json({ error: 'API key missing' });
}

if (apiKey !== VALID_API_KEY) {
return res.status(403).json({ error: 'Invalid API key' });
}

next();
};

router.post('/protected', apiKeyAuthMiddleware, (req, res) => {
res.status(200).json({ message: 'You have accessed a protected route!' });
});

module.exports = router;
2 changes: 2 additions & 0 deletions packages/bruno-tests/src/auth/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const authBearer = require('./bearer');
const authBasic = require('./basic');
const authWsse = require('./wsse');
const authCookie = require('./cookie');
const apiKey = require('./apiKey');
const authOAuth2PasswordCredentials = require('./oauth2/passwordCredentials');
const authOAuth2AuthorizationCode = require('./oauth2/authorizationCode');
const authOAuth2ClientCredentials = require('./oauth2/clientCredentials');
Expand All @@ -16,5 +17,6 @@ router.use('/bearer', authBearer);
router.use('/basic', authBasic);
router.use('/wsse', authWsse);
router.use('/cookie', authCookie);
router.use('/apiKey', apiKey);

module.exports = router;

0 comments on commit e068efc

Please sign in to comment.