Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/curityio/pkce-javascript-example
JavaScript SPA showing how to handle PKCE in an OpenID Connect flow
https://github.com/curityio/pkce-javascript-example
code-example oauth2 openid-connect spa
Last synced: about 2 months ago
JSON representation
JavaScript SPA showing how to handle PKCE in an OpenID Connect flow
- Host: GitHub
- URL: https://github.com/curityio/pkce-javascript-example
- Owner: curityio
- License: apache-2.0
- Created: 2020-02-28T04:48:38.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2023-01-04T08:15:29.000Z (about 2 years ago)
- Last Synced: 2023-12-07T23:28:31.874Z (about 1 year ago)
- Topics: code-example, oauth2, openid-connect, spa
- Language: HTML
- Homepage: https://curity.io/resources/learn/javascript-pkce-client/
- Size: 27.3 KB
- Stars: 51
- Watchers: 7
- Forks: 13
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# A Simple JavaScript PKCE Example
[![Quality](https://img.shields.io/badge/quality-demo-red)](https://curity.io/resources/code-examples/status/)
[![Availability](https://img.shields.io/badge/availability-source-blue)](https://curity.io/resources/code-examples/status/)## Introduction
The OAuth Code Flow is one of the more typical and flexible token flows, and, with that, one of the most popular. The details of this flow are not covered by this article, but can be found in the [code flow overview](https://curity.io/resources/learn/oauth-code-flow) article on the Curity Web site.
Proof Key for Code Exchange (PKCE) is a technique described in [RFC7636](https://www.rfc-editor.org/rfc/rfc7636), and is used to mitigate the risk of the authorization code being hijacked. More details on how to configure the Curity Identity Server to enable PKCE can be found in the [configuring PKCE](https://curity.io/resources/learn/pkce/) tutorial, and [further details on PKCE](https://curity.io/resources/learn/oauth-pkce/) can also be found on the same site.
The rest of this writeup explains how these technologies can be used in the JavaScript programming language. It is intentionally simple, so that the concepts are not obscured by superfluous details.
## Configuration
### Client
The client -- the HTML page -- needs to be configured with the client ID. In this example, the ID is `public-test-client`. If certain scopes are desired, these should be configured as well.
```JavaScript
const clientId = "public-test-client";
```#### Creating the Verifier
This function generates a random string (the verifier) that is later signed before it is sent to the authorization server, to Curity.
```JavaScript
function generateRandomString(length) {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}return text;
}
```#### Hashing the Verifier
The Web crypto API is used to hash the verifier using SHA-256. This transformed version is called the code challenge.
```JavaScript
async function generateCodeChallenge(codeVerifier) {
var digest = await crypto.subtle.digest("SHA-256",
new TextEncoder().encode(codeVerifier));return btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_')
}
```Note that Javascript crypto services require that the `index.html` is served in a [secure context](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts) — either from **(*.)localhost** or via **HTTPS**.
To enable secure context do one of the following:
- add an `/etc/hosts` entry like `127.0.0.1 public-test-client.localhost` and load the site from there, or
- enable SSL using something like [letsencrypt](https://letsencrypt.org/), or
- refer to this [stackoverflow article](https://stackoverflow.com/questions/46468104/how-to-use-subtlecrypto-in-chrome-window-crypto-subtle-is-undefined) for more alternatives.If Javascript crypto is not available the script will fall back to using a plain-text code challenge.
#### Storing the Verifier
Store the verification key between requests (using session storage).
```JavaScript
window.sessionStorage.setItem("code_verifier", codeVerifier);
```#### Sending the Code Challenge in the Authorization Request
The code challenge (the transformed, temporary verification secret) is passed to the authorization server as part of the authorization request. The method (`S256`, in our case) used to transform the secret is also passed with the request.
```JavaScript
var redirectUri = window.location.href.split('?')[0];
var args = new URLSearchParams({
response_type: "code",
client_id: clientId,
code_challenge_method: "S256",
code_challenge: codeChallenge,
redirect_uri: redirectUri
});
window.location = authorizeEndpoint + "/?" + args;
```#### Call the Token Endpoint with the Code and Verifier
The authorization code is passed in the POST request to the token endpoint along with the secret verifier key (retrieved from the session storage).
```JavaScript
xhr.responseType = 'json';
xhr.open("POST", tokenEndpoint, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send(new URLSearchParams({
client_id: clientId,
code_verifier: window.sessionStorage.getItem("code_verifier"),
grant_type: "authorization_code",
redirect_uri: location.href.replace(location.search, ''),
code: code
}));
```### OAuth Server
The OAuth server needs to be configured with a client that matches the one configured [above](#Client). Also, the redirect should be set. When using `npx` (described below), this will be `http://localhost:8080` by default if no port is provided. Additionally, scopes may be configured.
This can be created in the Curity Identity Server by merging this XML with the current configuration:
```xml
my-good-oauth-profile
as:oauth-service
public-test-client
true
http://localhost:8080/
false
```
## Serving the Sample HTML File
The HTML needs to be served somehow from a Web server. Because the client is just a static HTML page, this can be done with a trivial server configuration. Below are a couple of ways to easily serve the static HTML page:
```sh
$ npx http-server -p
``````sh
$ php -S :
``````sh
$ python -m SimpleHTTPServer
```These will not use TLS, but are fast and easy ways to serve the HTML file without setting up any infrastructure.
## License
The code and samples in this repository are licensed under the [Apache 2 license](LICENSE).
## Questions
For questions and comments, contact Curity AB:
> [email protected]
> https://curity.ioCopyright (C) 2020 Curity AB.