Skip to content

Commit 19b8501

Browse files
committed
feat: enhance okta sdk oauth
1 parent 286c19d commit 19b8501

9 files changed

Lines changed: 67 additions & 2 deletions

File tree

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ const client = new okta.Client({
102102
keyId: 'kidValue'
103103
});
104104
```
105+
```js
106+
const client = new okta.Client({
107+
orgUrl: 'https://dev-1234.oktapreview.com/',
108+
authorizationMode: 'ClientSecret',
109+
clientId: '{oauth application ID}',
110+
clientSecret: '{oauth application Secret}',
111+
scopes: ['okta.users.manage']
112+
});
113+
```
105114

106115
The `privateKey` can be passed in the following ways:
107116
- As a JSON encoded string of a JWK object

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@
2020
"jest": "JEST_JUNIT_OUTPUT_DIR=./test-reports jest --coverage --ci --testResultsProcessor=jest-junit test/jest/*.js",
2121
"predocs": "rimraf ./jsdocs && mkdir jsdocs/ && ./utils/make-jsdoc-readme.js > ./jsdocs/jsdoc-temp.md",
2222
"docs": "./node_modules/.bin/jsdoc src/ -c ./docs/config.json -d ./jsdocs/ -P ./package.json -R ./jsdocs/jsdoc-temp.md -r",
23-
"test:integration": "yarn test:integration:oauth && yarn test:integration:ssws",
23+
"test:integration": "yarn test:integration:oauth && yarn test:integration:ssws && yarn test:integration:clientsecret",
2424
"test:integration:ssws": "TEST_TYPE=it OKTA_CLIENT_AUTHORIZATIONMODE=SSWS mocha test/it/*.ts",
2525
"test:integration:oauth": "TEST_TYPE=it OKTA_CLIENT_AUTHORIZATIONMODE=PrivateKey mocha test/it/user-get.ts",
26+
"test:integration:clientsecret": "TEST_TYPE=it OKTA_CLIENT_AUTHORIZATIONMODE=ClientSecret mocha test/it/user-get.ts",
2627
"test:unit": "TEST_TYPE=unit mocha test/unit/*.js",
2728
"test:types": "tsd && tsc --noEmit --isolatedModules --importsNotUsedAsValues error src/types/**/*.ts",
2829
"test": "yarn eslint && yarn test:types && yarn test:unit && yarn test:integration && yarn jest",

src/client.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class Client {
8181
errors.push('Okta Org URL not provided');
8282
}
8383

84-
if (!parsedConfig.client.token && parsedConfig.client.authorizationMode !== 'PrivateKey') {
84+
if (!parsedConfig.client.token && parsedConfig.client.authorizationMode === 'SSWS') {
8585
errors.push('Okta API token not provided');
8686
}
8787

@@ -95,6 +95,16 @@ class Client {
9595
if (!parsedConfig.client.privateKey) {
9696
errors.push('Private Key not provided');
9797
}
98+
} else if (parsedConfig.client.authorizationMode === 'ClientSecret') {
99+
if (!parsedConfig.client.clientId) {
100+
errors.push('Okta Client ID not provided');
101+
}
102+
if (!parsedConfig.client.scopes) {
103+
errors.push('Scopes not provided');
104+
}
105+
if (!parsedConfig.client.clientSecret) {
106+
errors.push('Okta Client Secret not provided');
107+
}
98108
} else if (parsedConfig.client.authorizationMode !== 'SSWS') {
99109
errors.push('Unknown Authorization Mode');
100110
}
@@ -111,6 +121,11 @@ class Client {
111121
this.privateKey = parsedConfig.client.privateKey;
112122
this.keyId = parsedConfig.client.keyId;
113123
this.oauth = new OAuth(this);
124+
} else if (this.authorizationMode === 'ClientSecret') {
125+
this.clientId = parsedConfig.client.clientId;
126+
this.scopes = parsedConfig.client.scopes.split(' ');
127+
this.clientSecret = parsedConfig.client.clientSecret;
128+
this.oauth = new OAuth(this);
114129
}
115130

116131
this.http = new Http({

src/config-loader.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class ConfigLoader {
2828
orgUrl: '',
2929
token: '',
3030
clientId: '',
31+
clientSecret: '',
3132
scopes: '',
3233
privateKey: '',
3334
keyId: '',

src/oauth.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
const { makeJwt } = require('./jwt');
1515
const Http = require('./http');
16+
const { base64urlEncode } = require('njwt');
1617

1718
function formatParams(obj) {
1819
var str = [];
@@ -44,6 +45,33 @@ class OAuth {
4445
return Promise.resolve(this.accessToken);
4546
}
4647

48+
if (this.client.authorizationMode === 'ClientSecret') {
49+
const base64Creds = base64urlEncode(`${this.client.clientId}:${this.client.clientSecret}`);
50+
const params = formatParams({
51+
grant_type: 'client_credentials',
52+
scope: this.client.scopes.join(' ')
53+
});
54+
return this.client.requestExecutor.fetch({
55+
url: `${this.client.baseUrl}/oauth2/default/v1/token`,
56+
method: 'POST',
57+
body: params,
58+
headers: {
59+
Accept: 'application/json',
60+
Authorization: `Basic ${base64Creds}`,
61+
'cache-control': 'no-cache',
62+
'content-type': 'application/x-www-form-urlencoded'
63+
}
64+
})
65+
.then(Http.errorFilter)
66+
.then(res => {
67+
return res.json();
68+
})
69+
.then(accessToken => {
70+
this.accessToken = accessToken;
71+
return this.accessToken;
72+
});
73+
}
74+
4775
const endpoint = '/oauth2/v1/token';
4876
return this.getJwt(endpoint)
4977
.then(jwt => {

src/types/client.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export declare class Client {
5858
baseUrl: string;
5959
apiToken: string;
6060
clientId: string;
61+
clientSecret: string;
6162
scopes: string[];
6263
privateKey: string;
6364
keyId: string;

src/types/configuration.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export declare interface V2Configuration {
1919
orgUrl?: string,
2020
token?: string,
2121
clientId?: string,
22+
clientSecret?: string,
2223
scopes?: string[],
2324
requestExecutor?: RequestExecutor,
2425
authorizationMode?: string,

test/it/user-get.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ const client = new Client({
1212
scopes: ['okta.users.manage'],
1313
orgUrl: orgUrl,
1414
token: process.env.OKTA_CLIENT_TOKEN,
15+
clientId: process.env.OKTA_CLIENT_ID,
16+
clientSecret: process.env.OKTA_CLIENT_SECRET,
1517
requestExecutor: new DefaultRequestExecutor()
1618
});
1719

test/unit/config-loader.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ describe('ConfigLoader', () => {
2222
orgUrl: '',
2323
token: '',
2424
clientId: '',
25+
clientSecret: '',
2526
scopes: '',
2627
privateKey: '',
2728
keyId: '',
@@ -52,6 +53,7 @@ describe('ConfigLoader', () => {
5253
orgUrl: '',
5354
token: '',
5455
clientId: '',
56+
clientSecret: '',
5557
scopes: '',
5658
privateKey: '',
5759
keyId: '',
@@ -77,6 +79,7 @@ describe('ConfigLoader', () => {
7779
token: '',
7880
authorizationMode: 'PrivateKey',
7981
clientId: '',
82+
clientSecret: '',
8083
scopes: '',
8184
privateKey: '',
8285
keyId: '',
@@ -101,6 +104,7 @@ describe('ConfigLoader', () => {
101104
authorizationMode: 'SSWS',
102105
token: '',
103106
clientId: '',
107+
clientSecret: '',
104108
scopes: '',
105109
privateKey: '',
106110
keyId: '',
@@ -132,6 +136,7 @@ describe('ConfigLoader', () => {
132136
token: '',
133137
authorizationMode: '',
134138
clientId: '',
139+
clientSecret: '',
135140
scopes: '',
136141
privateKey: '',
137142
keyId: '',
@@ -149,6 +154,7 @@ describe('ConfigLoader', () => {
149154
token: 'a',
150155
authorizationMode: 'SSWS',
151156
clientId: '',
157+
clientSecret: '',
152158
scopes: '',
153159
privateKey: '',
154160
keyId: '',
@@ -166,6 +172,7 @@ describe('ConfigLoader', () => {
166172
token: 'a',
167173
authorizationMode: 'PrivateKey',
168174
clientId: '',
175+
clientSecret: '',
169176
scopes: '',
170177
privateKey: '',
171178
keyId: '',

0 commit comments

Comments
 (0)