Skip to content

Commit

Permalink
feat: enhance okta sdk oauth
Browse files Browse the repository at this point in the history
  • Loading branch information
Astro2024 committed Nov 19, 2024
1 parent 286c19d commit 19b8501
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 2 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ const client = new okta.Client({
keyId: 'kidValue'
});
```
```js
const client = new okta.Client({
orgUrl: 'https://dev-1234.oktapreview.com/',
authorizationMode: 'ClientSecret',
clientId: '{oauth application ID}',
clientSecret: '{oauth application Secret}',
scopes: ['okta.users.manage']
});
```

The `privateKey` can be passed in the following ways:
- As a JSON encoded string of a JWK object
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
"jest": "JEST_JUNIT_OUTPUT_DIR=./test-reports jest --coverage --ci --testResultsProcessor=jest-junit test/jest/*.js",
"predocs": "rimraf ./jsdocs && mkdir jsdocs/ && ./utils/make-jsdoc-readme.js > ./jsdocs/jsdoc-temp.md",
"docs": "./node_modules/.bin/jsdoc src/ -c ./docs/config.json -d ./jsdocs/ -P ./package.json -R ./jsdocs/jsdoc-temp.md -r",
"test:integration": "yarn test:integration:oauth && yarn test:integration:ssws",
"test:integration": "yarn test:integration:oauth && yarn test:integration:ssws && yarn test:integration:clientsecret",
"test:integration:ssws": "TEST_TYPE=it OKTA_CLIENT_AUTHORIZATIONMODE=SSWS mocha test/it/*.ts",
"test:integration:oauth": "TEST_TYPE=it OKTA_CLIENT_AUTHORIZATIONMODE=PrivateKey mocha test/it/user-get.ts",
"test:integration:clientsecret": "TEST_TYPE=it OKTA_CLIENT_AUTHORIZATIONMODE=ClientSecret mocha test/it/user-get.ts",
"test:unit": "TEST_TYPE=unit mocha test/unit/*.js",
"test:types": "tsd && tsc --noEmit --isolatedModules --importsNotUsedAsValues error src/types/**/*.ts",
"test": "yarn eslint && yarn test:types && yarn test:unit && yarn test:integration && yarn jest",
Expand Down
17 changes: 16 additions & 1 deletion src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class Client {
errors.push('Okta Org URL not provided');
}

if (!parsedConfig.client.token && parsedConfig.client.authorizationMode !== 'PrivateKey') {
if (!parsedConfig.client.token && parsedConfig.client.authorizationMode === 'SSWS') {
errors.push('Okta API token not provided');
}

Expand All @@ -95,6 +95,16 @@ class Client {
if (!parsedConfig.client.privateKey) {
errors.push('Private Key not provided');
}
} else if (parsedConfig.client.authorizationMode === 'ClientSecret') {
if (!parsedConfig.client.clientId) {
errors.push('Okta Client ID not provided');
}
if (!parsedConfig.client.scopes) {
errors.push('Scopes not provided');
}
if (!parsedConfig.client.clientSecret) {
errors.push('Okta Client Secret not provided');
}
} else if (parsedConfig.client.authorizationMode !== 'SSWS') {
errors.push('Unknown Authorization Mode');
}
Expand All @@ -111,6 +121,11 @@ class Client {
this.privateKey = parsedConfig.client.privateKey;
this.keyId = parsedConfig.client.keyId;
this.oauth = new OAuth(this);
} else if (this.authorizationMode === 'ClientSecret') {
this.clientId = parsedConfig.client.clientId;
this.scopes = parsedConfig.client.scopes.split(' ');
this.clientSecret = parsedConfig.client.clientSecret;
this.oauth = new OAuth(this);
}

this.http = new Http({
Expand Down
1 change: 1 addition & 0 deletions src/config-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class ConfigLoader {
orgUrl: '',
token: '',
clientId: '',
clientSecret: '',
scopes: '',
privateKey: '',
keyId: '',
Expand Down
28 changes: 28 additions & 0 deletions src/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

const { makeJwt } = require('./jwt');
const Http = require('./http');
const { base64urlEncode } = require('njwt');

function formatParams(obj) {
var str = [];
Expand Down Expand Up @@ -44,6 +45,33 @@ class OAuth {
return Promise.resolve(this.accessToken);
}

if (this.client.authorizationMode === 'ClientSecret') {
const base64Creds = base64urlEncode(`${this.client.clientId}:${this.client.clientSecret}`);
const params = formatParams({
grant_type: 'client_credentials',
scope: this.client.scopes.join(' ')
});
return this.client.requestExecutor.fetch({
url: `${this.client.baseUrl}/oauth2/default/v1/token`,
method: 'POST',
body: params,
headers: {
Accept: 'application/json',
Authorization: `Basic ${base64Creds}`,
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded'
}
})
.then(Http.errorFilter)
.then(res => {
return res.json();
})
.then(accessToken => {
this.accessToken = accessToken;
return this.accessToken;
});
}

const endpoint = '/oauth2/v1/token';
return this.getJwt(endpoint)
.then(jwt => {
Expand Down
1 change: 1 addition & 0 deletions src/types/client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export declare class Client {
baseUrl: string;
apiToken: string;
clientId: string;
clientSecret: string;
scopes: string[];
privateKey: string;
keyId: string;
Expand Down
1 change: 1 addition & 0 deletions src/types/configuration.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export declare interface V2Configuration {
orgUrl?: string,
token?: string,
clientId?: string,
clientSecret?: string,
scopes?: string[],
requestExecutor?: RequestExecutor,
authorizationMode?: string,
Expand Down
2 changes: 2 additions & 0 deletions test/it/user-get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const client = new Client({
scopes: ['okta.users.manage'],
orgUrl: orgUrl,
token: process.env.OKTA_CLIENT_TOKEN,
clientId: process.env.OKTA_CLIENT_ID,
clientSecret: process.env.OKTA_CLIENT_SECRET,
requestExecutor: new DefaultRequestExecutor()
});

Expand Down
7 changes: 7 additions & 0 deletions test/unit/config-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ describe('ConfigLoader', () => {
orgUrl: '',
token: '',
clientId: '',
clientSecret: '',
scopes: '',
privateKey: '',
keyId: '',
Expand Down Expand Up @@ -52,6 +53,7 @@ describe('ConfigLoader', () => {
orgUrl: '',
token: '',
clientId: '',
clientSecret: '',
scopes: '',
privateKey: '',
keyId: '',
Expand All @@ -77,6 +79,7 @@ describe('ConfigLoader', () => {
token: '',
authorizationMode: 'PrivateKey',
clientId: '',
clientSecret: '',
scopes: '',
privateKey: '',
keyId: '',
Expand All @@ -101,6 +104,7 @@ describe('ConfigLoader', () => {
authorizationMode: 'SSWS',
token: '',
clientId: '',
clientSecret: '',
scopes: '',
privateKey: '',
keyId: '',
Expand Down Expand Up @@ -132,6 +136,7 @@ describe('ConfigLoader', () => {
token: '',
authorizationMode: '',
clientId: '',
clientSecret: '',
scopes: '',
privateKey: '',
keyId: '',
Expand All @@ -149,6 +154,7 @@ describe('ConfigLoader', () => {
token: 'a',
authorizationMode: 'SSWS',
clientId: '',
clientSecret: '',
scopes: '',
privateKey: '',
keyId: '',
Expand All @@ -166,6 +172,7 @@ describe('ConfigLoader', () => {
token: 'a',
authorizationMode: 'PrivateKey',
clientId: '',
clientSecret: '',
scopes: '',
privateKey: '',
keyId: '',
Expand Down

0 comments on commit 19b8501

Please sign in to comment.