-
Notifications
You must be signed in to change notification settings - Fork 265
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
PKCE implementation #205
PKCE implementation #205
Changes from 50 commits
b0624fa
8a4e4c8
c140fd0
839139c
23857b6
3901d65
2e89506
1f26bfa
8421b1c
6ee3148
0f3cc7b
aa9ccc7
06b8dfa
7650c24
d53cc8c
71dc682
5d3b428
caf4e4e
6958175
3739e47
173e9af
5d68ca5
3e41320
ec2b368
a6ebafa
bbcf753
5cc5c98
4f46c08
a9931f2
6beae1d
cd5e5da
0746ffc
8a92988
1cbfa75
b078905
9c308b1
ce798ce
1c99d55
6e3c197
9ddc284
82e1ca9
5589c7b
85e95eb
365d129
0322b0c
e386714
dc1adca
4f11f53
ce15188
d384a71
d145903
0ecc4fc
e13491e
1cd3306
d8cfe0a
d702a20
29c1974
b438da1
24deee5
c2f1eb1
be807b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,6 @@ | |
/buildtools | ||
/dist | ||
/target | ||
/node_modules | ||
node_modules | ||
*.config.js | ||
/lib/config.js |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -162,8 +162,10 @@ tokenManager: { | |
| `issuer` | Specify a custom issuer to perform the OIDC flow. Defaults to the base url parameter if not provided. | | ||
| `clientId` | Client Id pre-registered with Okta for the OIDC authentication flow. | | ||
| `redirectUri` | The url that is redirected to when using `token.getWithRedirect`. This must be pre-registered as part of client registration. If no `redirectUri` is provided, defaults to the current origin. | | ||
| `grantType` | Specify grantType for this Application. Supported types are `implicit` and `authorization_code`. Defaults to `implicit` | | ||
| `authorizeUrl` | Specify a custom authorizeUrl to perform the OIDC flow. Defaults to the issuer plus "/v1/authorize". | | ||
| `userinfoUrl` | Specify a custom userinfoUrl. Defaults to the issuer plus "/v1/userinfo". | | ||
| `tokenUrl` | Specify a custom tokenUrl. Defaults to the issuer plus "/v1/token". | | ||
| `ignoreSignature` | ID token signatures are validated by default when `token.getWithoutPrompt`, `token.getWithPopup`, `token.getWithRedirect`, and `token.verify` are called. To disable ID token signature validation for these methods, set this value to `true`. | | ||
| | This option should be used only for browser support and testing purposes. | | ||
|
||
|
@@ -191,6 +193,28 @@ var config = { | |
var authClient = new OktaAuth(config); | ||
``` | ||
|
||
##### PKCE OAuth flow | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OAuth -> OAuth 2.0 We don't need to replace all other occurrences of this, but we should make sure we're referencing the correct protocol in our headings. |
||
|
||
By default the `implicit` OAuth flow will be used. It is widely supported by most browsers. PKCE is a newer flow which is more secure, but does require certain capabilities from the browser. | ||
|
||
To use PKCE flow, set `grantType` to `authorization_code` in your config. | ||
|
||
```javascript | ||
|
||
var config = { | ||
grantType: 'authorization_code', | ||
|
||
// other config | ||
issuer: 'https://{yourOktaDomain}/oauth2/default', | ||
}; | ||
|
||
var authClient = new OktaAuth(config); | ||
``` | ||
|
||
If the user's browser does not support PKCE, an exception will be thrown. You can test if a browser supports PKCE before construction with this static method: | ||
|
||
`OktaAuth.features.isPKCESupported()` | ||
|
||
### Optional configuration options | ||
|
||
### `httpRequestClient` | ||
|
@@ -212,7 +236,8 @@ var config = { | |
// headers: { | ||
// headerName: headerValue | ||
// }, | ||
// data: postBodyData | ||
// data: postBodyData, | ||
// withCredentials: true|false, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Maybe throw a line to explain why they might need There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If they are providing the httpRequest agent, they just need to honor the setting. It is a common flag for ajax libraries. |
||
// } | ||
return Promise.resolve(/* a raw XMLHttpRequest response */); | ||
} | ||
|
@@ -1445,7 +1470,12 @@ authClient.token.getWithRedirect(oauthOptions); | |
|
||
#### `token.parseFromUrl(options)` | ||
|
||
Parses the access or ID Tokens from the url after a successful authentication redirect. If an ID token is present, it will be [verified and validated](https://github.com/okta/okta-auth-js/blob/master/lib/token.js#L186-L190) before available for use. | ||
Parses the authorization code, access, or ID Tokens from the URL after a successful authentication redirect. | ||
|
||
If an authorization code is present, it will be exchanged for token(s) by posting to the `tokenUrl` endpoint. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to clarify - the resolved return value from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. correct |
||
|
||
The ID token will be [verified and validated](https://github.com/okta/okta-auth-js/blob/master/lib/token.js#L186-L190) before available for use. | ||
aarongranick-okta marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
```javascript | ||
authClient.token.parseFromUrl() | ||
|
@@ -1718,7 +1748,7 @@ yarn install | |
| Command | Description | | ||
| --------------------- | ------------------------------ | | ||
| `yarn build` | Build the SDK with a sourcemap | | ||
| `yarn test` | Run unit tests using Jest | | ||
| `yarn test` | Run unit tests | | ||
| `yarn lint` | Run eslint linting | | ||
|
||
## Contributing | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,11 +13,18 @@ | |
var fetch = require('cross-fetch'); | ||
|
||
function fetchRequest(method, url, args) { | ||
var body = args.data; | ||
|
||
// JSON encode body (if appropriate) | ||
if (body && args.headers && args.headers['Content-Type'] === 'application/json' && typeof body !== 'string') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we sure it will be 'Content-Type' and never 'content-type'? IIRC the spec is not case sensitive. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The header can be either, but looking up the key There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bump ^ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can definitely make this change. But in reality we are the only users of this code. We use it as a pluggable utility wrapper around another xhr lib. Anything we do here, we must duplicate that logic in our jqueryRequest and reqwestRequest objects as well. Previously EVERYTHING was JSON encoded. I am creating a small pinhole for the token POST to succeed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't we check these values to be safe? If our dependency on cross-fetch, an application and/or plugin modifies the headers to be lowercase, this check will fail. |
||
body = JSON.stringify(body); | ||
} | ||
|
||
var fetchPromise = fetch(url, { | ||
method: method, | ||
headers: args.headers, | ||
body: JSON.stringify(args.data), | ||
credentials: 'include' | ||
body: body, | ||
credentials: args.withCredentials === false ? 'omit' : 'include' | ||
}) | ||
.then(function(response) { | ||
var error = !response.ok; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/*! | ||
* Copyright (c) 2019-Present, Okta, Inc. and/or its affiliates. All rights reserved. | ||
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") | ||
* | ||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* | ||
* See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
|
||
// Karma configuration file, see link for more information | ||
// http://karma-runner.github.io/3.0/config/configuration-file.html | ||
|
||
/* global __dirname */ | ||
var path = require('path'); | ||
var REPORTS_DIR = path.join(__dirname, 'build2', 'reports', 'karma'); | ||
|
||
var webpackConf = { | ||
devtool: 'inline-source-map', | ||
resolve: { | ||
alias: { | ||
'@okta/okta-auth-js': path.join(__dirname, 'lib/browser/browserIndex.js') | ||
} | ||
}, | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.js$/, | ||
use: { loader: 'istanbul-instrumenter-loader' }, | ||
enforce: 'post', | ||
include: [ | ||
path.resolve(__dirname, 'lib') | ||
] | ||
} | ||
] | ||
} | ||
}; | ||
|
||
module.exports = function (config) { | ||
config.set({ | ||
basePath: '', | ||
frameworks: ['jasmine', 'jquery-3.3.1'], | ||
plugins: [ | ||
'karma-jasmine', | ||
'karma-chrome-launcher', | ||
'karma-coverage-istanbul-reporter', | ||
'karma-webpack', | ||
'karma-jquery', | ||
'karma-sourcemap-loader' | ||
], | ||
files: [ | ||
{ pattern: './test/karma/main.js', watched: false } | ||
], | ||
preprocessors: { | ||
'test/karma/main.js': ['webpack', 'sourcemap'] | ||
}, | ||
webpack: webpackConf, | ||
webpackMiddleware: { | ||
stats: 'normal', | ||
}, | ||
client:{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style-nit: Space after |
||
// Passing specific test to run | ||
// but this works only with `karma start`, not `karma run`. | ||
test: config.test, | ||
clearContext: false // leave Jasmine Spec Runner output visible in browser | ||
}, | ||
coverageIstanbulReporter: { | ||
dir: REPORTS_DIR, | ||
reports: [ 'html', 'lcovonly' ], | ||
fixWebpackSourcePaths: true | ||
}, | ||
reporters: ['progress', 'coverage-istanbul'], | ||
port: 9876, | ||
colors: true, | ||
logLevel: config.LOG_INFO, | ||
autoWatch: true, | ||
browsers: ['ChromeHeadlessNoSandbox'], | ||
customLaunchers: { | ||
ChromeHeadlessNoSandbox: { | ||
base: 'ChromeHeadless', | ||
flags: ['--no-sandbox'] | ||
} | ||
}, | ||
singleRun: false | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,13 +37,19 @@ function OktaAuthBuilder(args) { | |
issuer: util.removeTrailingSlash(args.issuer), | ||
authorizeUrl: util.removeTrailingSlash(args.authorizeUrl), | ||
userinfoUrl: util.removeTrailingSlash(args.userinfoUrl), | ||
tokenUrl: util.removeTrailingSlash(args.tokenUrl), | ||
grantType: args.grantType, | ||
redirectUri: args.redirectUri, | ||
httpRequestClient: args.httpRequestClient, | ||
storageUtil: args.storageUtil, | ||
transformErrorXHR: args.transformErrorXHR, | ||
headers: args.headers | ||
}; | ||
|
||
if (this.options.grantType === 'authorization_code' && !sdk.features.isPKCESupported()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't we also need this statement whenever There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A developer CAN override There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be trivial to bring it back: dc1adca#diff-2c8402d8ca2c5c319eb971f5bdf5ac4dR37 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. adding this back in. |
||
throw new AuthSdkError('This browser doesn\'t support PKCE'); | ||
} | ||
|
||
this.userAgent = 'okta-auth-js-' + config.SDK_VERSION; | ||
|
||
// Digital clocks will drift over time, so the server | ||
|
@@ -151,6 +157,10 @@ proto.features.isTokenVerifySupported = function() { | |
return typeof crypto !== 'undefined' && crypto.subtle && typeof Uint8Array !== 'undefined'; | ||
}; | ||
|
||
proto.features.isPKCESupported = function() { | ||
return proto.features.isTokenVerifySupported(); | ||
}; | ||
|
||
// { username, password, (relayState), (context) } | ||
proto.signIn = function (opts) { | ||
var sdk = this; | ||
|
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.
style-nit: Adhere to the existing style of surrounding
grantType
in the description with back-ticks.