CYM-Identity tries to follow oAuth and OpenID Connect specifications and therefore is unopinionated when it comes to libraries.
In order to get you started with your SPA, we recommend that you use oidc-client-js
This guide only applies to Single Page Applications which do not have a dedicated backend. If you do have a dedicated backend, you must use the Web App guide instead

Set up a Single Page Application

If you haven't done it yet, you need to create an Application following the documentation
We strongly recommend that you only use the authorization_code grant.

Set up your API

By design, a Single Page Application will consume APIs hosted by a Resource Server.
Follow the instructions in the documentation to create your Resource Server and Protected Resources.

Add the library to your environment

Follow the instructions in oidc-client-js to add the appropriate dependencies
1const issuer = `https://${realm.url}/oauth/${realm.name}`;
2const settings = {
3 authority: `${issuer}/.well-known/openid-configuration`,
4 client_id: 'YOUR_CLIENT_ID',
5 redirect_uri: 'YOUR_REDIRECT_URI',
6 post_logout_redirect_uri: 'YOUR_POST_LOGOUT_REDIRECT_URI', // required to have a successful logout experience
7 response_type: "code",
8 scope: 'openid offline_access profile email address custom_scope', // Only use the scopes that have been assigned to this particular client
9 automaticSilentRenew: false,
10 loadUserInfo: false,
11 revokeAccessTokenOnSignout: true, // We highly recommend to revoke access_tokens on signout
12} as Oidc.UserManagerSettings;
13const mgr = new Oidc.UserManager(settings);

Authenticate your users

Now that everything is set up, you can start authenticating your users.
When your users are ready to authenticate, you can trigger an authentication request.
1const someState = {'hello' : 'world'};
2mgr.signinRedirect({
3 state: someState,
4 useReplaceToNavigate:true,
5 audience: 'RESOURCE_SERVER_CLIENT_ID', // use this parameter if your application will only consume the APIs from one resource server
6 acr_values: 'AAL1 AAL0', // space separated list of acr values requested. using this parameters maps to the standard openid voluntary claim
7}).then(function() {
8 console.log("signinRedirect done");
9}).catch(function(err) {
10 console.log(err);
11});
After a successfull authentication, the user will be redirected to your application.
Each logged in user (employee, customer, partner, ...) needs to hold a CYM-Identity License. Add it as part of mass assignment or through your registration flow.
Add the following code in your redirect_uri page
1try {
2 const user = await mgr.signinCallback({
3 audience: 'RESOURCE_SERVER_CLIENT_ID', // If you haven't specified an audience or resource in the authentication request, you can specify an API during the authorization_code exchange
4 });
5 const state = user.state;
6 console.log(state.hello === 'world'); // true
7} catch (ex) {
8 // Handle authorization_code exchange errors here
9}
You can now use the access_token to consume APIs.
1const data = await fetch('https://resource.server/resource', {
2 method: 'GET',
3 headers : {
4 'authorization' : 'Bearer ' + user.access_token
5 }
6}).then(resp => resp.json());

Keeping your users authenticated

The access_tokens generated initially have a short lifetime, and you'll need new ones to keep accessing APIs on behalf of the user. Once an access_token has expired, you'll get a 401 response from an API.
1try {
2 const user = await mgr.signinSilent({
3 audience: 'RESOURCE_SERVER_CLIENT_ID',
4 })
5} catch (ex) {
6 // Handle errors here
7}

Accessing more APIs

When you made the previous request, you chose a specific ResourceServer to which you needed access. If you need an access_token scoped to a different Resource Or ResourceServer, you can request for it

Audience

1try {
2 const user = await mgr.signinSilent({
3 audience: 'SAME_OR_DIFFERENT_RESOURCE_SERVER_CLIENT_ID', // You can specify a different resource or audience in this request in order to get a new access_token for a different audience
4 })
5} catch (ex) {
6 // Handle errors here
7}

Resource

1try {
2 const user = await mgr.signinSilent({
3 resource: 'https://resource.url', // You can specify a resource URL
4 })
5} catch (ex) {
6 // Handle errors here
7}

Logout users

When your users are ready to logout, you can request a logout as follows.
1try {
2 await mgr.signoutRedirect({state:'some data'});
3} catch (ex) {
4 // Handle signout request errors
5}