Background
Previously we provided a Final SPA Overview and next we will show how to run the Final SPA on a Developer PC in a couple of different configurations.
Prerequisites
The scripts in this post are meant to be run from a Linux or macOS terminal, or a Git Bash shell on Windows. You also need to have an up to date version of Node.js installed.
Step 1: Download the GitHub Code
The SPA project is available here, and can be downloaded / cloned to your local PC with this command:
git clone https://github.com/gary-archer/oauth.websample.final
Step 2: Add Domains to your Computer
You will need to ensure that this blog’s web development domain points to your local PC, by making a local DNS entry in your hosts file, which will exist at one of these locations:
OS | Path |
---|---|
Windows | c:\system32\drivers\etc\hosts |
macOS / Linux | /etc/hosts |
Add entries as follows to represent the domain that serves the SPA’s static web content:
127.0.0.1 localhost web.authsamples-dev.com
::1 localhost
Step 3: View Components in an IDE
The web code consists of the following main areas:
Component | URL(s) |
---|---|
spa | The code for the SPA, which calls cross domain APIs using secure cookies |
webhost | A simple web host to use in local computer setups, to serve web static content to the browser |
cloudfront-extensions | Extensions used when the web host is the AWS content delivery network |
deployment | Resources used for managing and automating various deployment scenarios |
Step 4: View the React Code
The SPA has been updated to use React, though view classes have the same behavior as those from Earlier SPA Code Samples:
export function TitleView(props: TitleViewProps): JSX.Element {
return (
<div className='row'>
<div className='col-8 my-auto'>
<HeadingView />
</div>
{props.userInfo &&
<div className='col-4 my-auto'>
<UserInfoView {...props.userInfo}/>
</div>
}
</div>
);
}
React provides a modern toolset that will helps to enable productivity and capabilities for web development:
Benefit | Description |
---|---|
Markup | A strongly typed and secure way to work with markup and the DOM, including handling of dangerous input |
Components | A componentized development model, that promotes clean code and a separation of concerns |
Ecosystem | We can follow web development best practice techniques from the community |
Step 5: Build the Code
Open a terminal and run the following command. The script builds the SPA into JavaScript bundles and prepares a basic web host to serve them as static content:
./build.sh
This runs the frontend in watch mode, so that it can be developed with a pure SPA development model. The React code can be updated and changes quickly reflected in the browser:
Step 6: Configure SSL Trust
The build script downloads some development certificates:
To make the browser trust the certificate’s issuer you need to import the authsamples-dev.ca.pem root certificate into your Browser’s Trust Store:
Step 7: Run the App
Next start a second terminal window and run the following command, which will start the web host, then invoke the default browser at https://web.authsamples-dev.com/spa/:
./run.sh
Step 8: Login to the SPA
You will then be prompted to sign in, and can do so with this test credential:
- User: guestuser@mycompany.com
- Password: GuestPassword1
The SPA will then get data from a remote API hosted behind the AWS API Gateway. The SPA will then render its simple views:
Step 9: View Secure Cookies
The SPA no longer uses tokens and instead uses only the strongest cookies. When run on a development computer, it uses these cookie properties:
- HTTP Only
- Secure
- SameSite=strict
- Domain=api.authsamples-dev.com
- Path = /
- AES256 Encrypted
You can use browser tools to view secure cookies issued, which are for the API subdomain and not the web origin. The SPA does not require any cookies to download static content, and does not use cookies when the user performs navigation operations:
Step 10: View Updated SPA Configuration
In earlier samples, the SPA performed its own OpenID Connect work in JavaScript. This work is now done by remote token handler components, and the SPA code and configuration is therefore simplified:
{
"apiBaseUrl": "https://api.authsamples-dev.com/tokenhandler/investments",
"oauthAgentBaseUrl": "https://api.authsamples-dev.com/tokenhandler/oauth-agent"
}
Step 11: Understand Web Security Headers
The web host now writes a number of security headers, the most interesting of which is the Content Security Policy. This has the following values, since the SPA now only makes remote calls via its API domain:
content-security-policy: default-src 'none'; script-src 'self'; connect-src 'self' https://api.authsamples-dev.com; child-src 'self'; img-src 'self'; style-src 'self'; object-src 'none' frame-ancestors 'none'; base-uri 'self'; form-action 'self' strict-transport-security: max-age=63072000; includeSubdomains; preload x-frame-options: DENY x-xss-protection: 1; mode=block x-content-type-options: nosniff referrer-policy: same-origin
Local API Setup
It is also possible to run the Sample API that provides the SPA’s data on the local computer, but you then need to manage cookies for this routing. One way to do so is to run a local token handler. To do so, first ensure that a docker engine is installed, and also the envsubst tool.
Step A: Run the API
Select one of this blog’s final APIs from the below list, and follow its instructions, to run the API on port 446:
Step B: Update DNS
Next, add the local API subdomain to your computer’s hosts file:
127.0.0.1 localhost web.authsamples-dev.com apilocal.authsamples-dev.com
::1 localhost
Step C: Run the SPA against a Local API
To make the SPA connect to one of this blog’s final APIs, first ensure that the API is running. Then use a ‘LOCALAPI‘ command line argument when running the scripts described earlier:
./build.sh LOCALAPI
./run.sh LOCALAPI
This will run the utility token handler components in a small Docker Compose network. The SPA’s configuration will then be updated as follows, to route to the API via the local token handler rather than the cloud one:
{
"apiBaseUrl": "https://apilocal.authsamples-dev.com:444/demobrand/investments",
"oauthAgentBaseUrl": "https://apilocal.authsamples-dev.com:444/demobrand/oauth-agent"
}
Step D: Use the SPA and API
When you now use the SPA it will call the local API rather than a cloud API. The API behaviour includes logging output that is explained in later blog posts, under the API theme.
Step E: Understand Token Handler Deployment
To understand how I deploy the OAuth agent and OAuth proxy components, you can study my deployment resources. I use the Kong API Gateway and the following Docker Compose deployment settings:
version: '3.8'
services:
apigateway:
image: custom_kong:latest
hostname: apigateway-internal.authsamples-dev.com
extra_hosts:
- apilocal.authsamples-dev.com:host-gateway
ports:
- 444:8000
volumes:
- ../environments/docker-local/gateway-routes.yml:/usr/local/kong/declarative/kong.yml
- ../../certs/authsamples-dev.ssl.pem:/usr/local/share/certs/authsamples-dev.ssl.pem
- ../../certs/authsamples-dev.ssl.key:/usr/local/share/certs/authsamples-dev.ssl.key
- ../../certs/authsamples-dev.ca.pem:/usr/local/share/certs/authsamples-dev.ca.pem
environment:
KONG_DATABASE: 'off'
KONG_DECLARATIVE_CONFIG: '/usr/local/kong/declarative/kong.yml'
KONG_PROXY_LISTEN: '0.0.0.0:8000 ssl'
KONG_SSL_CERT: '/usr/local/share/certs/authsamples-dev.ssl.pem'
KONG_SSL_CERT_KEY: './usr/local/share/certs/authsamples-dev.ssl.key'
KONG_LUA_SSL_TRUSTED_CERTIFICATE: './usr/local/share/certs/authsamples-dev.ca.pem'
KONG_LOG_LEVEL: 'info'
KONG_PLUGINS: 'bundled,oauth-proxy'
KONG_NGINX_PROXY_PROXY_BUFFERS: '16 64k'
KONG_NGINX_PROXY_PROXY_BUFFER_SIZE: '64k'
KONG_NGINX_PROXY_LARGE_CLIENT_HEADER_BUFFERS: '16 64k'
oauthagent:
image: oauthagent:latest
hostname: oauthagent-internal.authsamples-dev.com
volumes:
- ../../certs/authsamples-dev.ssl.p12:/usr/oauth-agent/certs/authsamples-dev.ssl.p12
env_file:
- ../environments/docker-local/.env
The OAuth agent uses environment variables such as the following, to interact with the authorization server and for its cookie issuing:
PORT=8000
TRUSTED_WEB_ORIGIN='https://web.authsamples-dev.com'
ISSUER='https://cognito-idp.eu-west-2.amazonaws.com/eu-west-2_CuhLeqiE9'
AUTHORIZE_ENDPOINT='https://login.authsamples.com/oauth2/authorize'
TOKEN_ENDPOINT='https://login.authsamples.com/oauth2/token'
USERINFO_ENDPOINT='https://login.authsamples.com/oauth2/userInfo'
LOGOUT_ENDPOINT='https://login.authsamples.com/logout'
CLIENT_ID='7q5pope8rki7okarj2u8l4in7o'
CLIENT_SECRET='1d18g4v05sesjkv161borl012j009l7ooktnfs10ph9p6nkbbfl9'
REDIRECT_URI='https://web.authsamples-dev.com/spa/'
POST_LOGOUT_REDIRECT_URI='https://web.authsamples-dev.com/spa/loggedout'
SCOPE='openid profile https://api.authsamples.com/investments'
COOKIE_DOMAIN='apilocal.authsamples-dev.com'
COOKIE_NAME_PREFIX='mycompany'
COOKIE_ENCRYPTION_KEY='33be02f1b76feccf2c30a4847b0ad68d01756d7a9fb7f9a533b12b5d249a9c66'
CORS_ENABLED='true'
SERVER_CERT_P12_PATH='./certs/authsamples-dev.ssl.p12'
SERVER_CERT_P12_PASSWORD='Password1'
When using the token handler pattern you remotely deploy these components. You do not need to develop them. The frontend development setup is therefore focused solely on the user interface, in the same way as this blog’s earlier SPAs.
Step F: Free Docker Resources
To free resources in the Docker compose network, run this command:
Where Are We?
We have explained how to run the final web sample, which has more moving parts than earlier code samples. The React demo SPA can be run as a single component under development. The app is in control of its own OpenID Connect flow. After user logins, the SPA calls deployed API components using secure cookies.
Next Steps
- Next we will drill into some Coding Key Points for the Final SPA
- For a list of all blog posts see the Index Page