TSDN
CIAMBest PracticesSingle Page App

By a single-page website we understand that

  • you have a backend server that serves a single HTML page.
  • further interaction with the server is through Ajax, without refreshing the page.
  • a page reload is akin to starting a new session and will force an authentication/authorization flow
    • due to cookies maintained internally in CIAM, this flow may not (often, will not) be visible to the user

Security

To help ensure that your single-page application is secure, we mandate

  • use of TLS
  • using CORS to ensure that the only conversation with your server comes from your webpage;
  • using firewalls appropriately configured to avoid origin spoofing;
  • to avoid CSRF attacks, do not use cookies or url parameters for session management and avoid them for other uses;
  • data relevant to a session should be kept by your back-end and an id provided to the frontend
    • the frontend should only use the session id to obtain an access token and to terminate the session
    • access tokens can be used to access any TRAPI services, including by the brandbar
  • your backend will obtain access tokens by using the OAuth2 Authorization code flow to the appropriate server:
envissuerwell-known endpoint
dev

https://dev-token.auth.topcon.com

https://dev-token.auth.topcon.com/.well-known/openid-configuration
qa

https://qa-token.auth.topcon.com

https://qa-token.auth.topcon.com/.well-known/openid-configuration
production

https://token.auth.topcon.com

https://token.auth.topcon.com/.well-known/openid-configuration

Design:

Your application should provide the following endpoints

  • A page reload always creates a new session
  • login: provide a redirect to the authorization_endpoint fetched from the appropriate well-known endpoint from the table above.
    • you should probably use access_type=offline  to get a refresh token, and use this refresh token to obtain new access tokens when required.
    • you should also use PKCE challenge values to avoid attacks during the website login flow.
  • callback: complete the authorization process

    • exchange the code for OAuth2 tokens (requires client authorization credentials to be provided)

    • create a session

    • render the front page
  • switch: login to a different team (which is a normal token exchange, but the parameter switch=bp  is passed to code generation)
  • logout: log out of your application. It's up to you to decide if that also means logging out of Topcon apps entirely; our sample code shows how to do this if you want to do so.
  • token: you will need an endpoint that takes a session value and returns a valid access token.
    • For protection from cross-site forgery, pass the session value in a header.
    • This endpoint will be called from your page via Ajax. For ease of use, It should return a value of the form

      { "access_token": "ey.....", expiry: 12345677 }

Example 

We have written some code to demonstrate using go libraries to achieve integration with CIAM Phase 1.5.

This code integrates OAuth2 back-end processing with the Topcon brand-bar in the front end.

The code is available in full in singlepage.zip

Authorization Code

Specifically we use

The OAuth2-specific code is shown in the fileoauthorize.go oauthorize.go . This provides code to handle the following routes:

  • / : the login route (which doesn't need a name)
  • /auth.callback  : OAuth callback which exchanges an Authorization code for an access token;
  • /auth.switch  : Route used to change teams;
  • /logout  : Work towards a functional log out facility. Further configuration is required, depending on the client.
  • /auth.token : Get hold of the access token

To use the example you will need to know:

  • It will interface with our QA token endpoint
  • the scope required for Phase 1.5 ( topcon.ciam.phase.1.5  ) is built in
  • you need to provide environment variables called CLIENT_ID and CLIENT_SECRET.
  • the example will run a server on port 3434 but you can reconfigure this using env variable REDIRECT_PORT.
  • the example has simple stores for sensitive data; this is held in memory (and so die with the server); you will want to have a more robust set-up in a real application (including lifetimes)
    • store maps (sessionId → token-object) as this is the full state we need for auth;
    • verifierStore is used by auth to hide the verifier value. It maps (key → verifier) and passes the key as the state  value. This means other parties cannot access the verifier itself.
    • endSessionStore maps (key→sessionid), where these keys are only useful for logging out.

The example provides the following public members:

  • NewOAuthorize  creates a new object for you that does the Oauth heavy lifting;
  • AddHandlers  will add the required OAuth handlers to an existing mux.Router 

Web Page

The web server serves a single, and simple, page.

  • The page is integrated with the brand bar, but otherwise is essentially empty.
  • The page is rendered using the golang template library to inject the CSRFToken into it so that it can in turn use the /auth.token  route. This is required by the brand-bar.
  • The pre-rendered file is index.htmlindex.html. It is injected into the server in fixtures.go which is generated by the go-bindata utility.

Server Code

The file server.go  shows how to integrate the OAuthorize   code into a web server.

  • It sets up a mux.Router  to do the routing
  • It adds the necessary auth handlers using AddHandlers  
  • It adds CORS. These settings should be carefully considered in practise.
  • Finally, it runs the server.

Files