User Session Avatar¶
The component serves several purposes:
- Nice and configurable interface for user interaction.
- Inactivity detection in client side through
SQ.sso
. - Single Sign-Out implementation in client side.
- Cookie validation (if using signed cookie)
- Verifies signature in Cookie to avoid external tampering.
- Verifies several claims from the application's access token against the cookie.
The readme contains complete documentation about its implementation and configuration, but see below recommended steps for implementation.
Prerequisites¶
The frontend environment requires:
npm
for dependency management- a bundler (like
webpack
) react
andreact-dom
installed as dependencies- have configured Nexus registry for
@sequel
packages (see this)
Your application does not need to be react, in fact is a simple component that works smooth even in plain JS or Angular. But npm
and a bundler are mandatory in order to properly use the component and its dependencies.
Integration¶
The component is implementation agnostic in the oidc client side. It requires some mappings in order to talk with it, but also allows developers to adjust the behaviour in some scenarios.
README
Do not forget to read the README of the component for more detailed documentation of the configuration and theme customization.
The authentication service can be implemented with oidc-client
, your own implementation or whatever. Just ensure to follow the steps for implementing the callbacks and profile mapping.
The user
object must be mapped from a profile or JWT claims. Ensure to ask for openid profile
scopes (email
just in case it does not include it) when asking for an access token. Then, the mapping is easy as:
Property | Claim |
---|---|
userName |
sub |
firstName |
given_name |
lastName |
family_name |
email |
email |
oidc-client
When using oidc-client
, you can map the properties like this:
const user = await userManager.getUser();
const userProp = {
userName: user.profile.sub,
firstName: user.profile.given_name,
lastName: user.profile.family_name,
email: user.profile.email,
};
Next step is to configure actions when several events happen (urls
prop). First of all, configure the authentication url, this is implementation specific and it is out of scope. Next is to implement the renewSsoCookie
, logOut
and refreshSession
.
renewSsoCookie
: URL or Callback or empty.- URL: When the component needs to refresh the
SQ.sso
cookie, will call this endpoint usingGET
. It can also be a function that returns anstring
. - Callback: Calls the function to do the renew cookie operation. Can be a simple API call that does just exactly this.
- Empty: Do not fill property to do nothing (not recommended).
- URL: When the component needs to refresh the
logOut
: URL or Callback or empty.- URL: When the component should make a log out process, redirects to that URL. It can also be a function that returns an
string
. - Callback: Calls the function to do the log out. Can be a simple API call or the end session flow of OIDC.
- Empty: Does nothing (not recommended).
- URL: When the component should make a log out process, redirects to that URL. It can also be a function that returns an
refreshSession
: Callback or empty.- Callback: Calls the function to do a session refresh. That is: to remove all information and access tokens of the current user and ask for new ones without doing a log out/end session.
- Empty: Does what
logOut
is configured to do (not recommended).
oidc-client
To implement logOut
and refreshSession
using oidc-client
, you can do the following:
const logOut = async () => {
// this redirects the webpage to the *end session* endpoint
await userManager.signoutRedirect();
};
const refreshSession = async () => {
// removes all access tokens and user information
await userManager.removeUser();
// log in process
await userManager.clearStaleState(); // optional
await userManager.signinRedirect();
};
For improved debug experience, the prop loggingEnabled
can be set to true to log in console a lot of debug information around the internal process. If there is an issue in the component, it is better to include a trace of those logs.
Theming is out of scope of this document, please read the README for more detailed information.
angular.js¶
Integration using Angular.JS can be done with a simple directive, but depends on your implementation of the services which may affect the final implementation.
import { render } from 'react-dom';
import { UserSessionAvatar } from '@sequel/sequel.web.usersessionavatar';
import type OidcService from '.../oidc.service'; // your authentication service
const UserSessionAvatarDirective = ($q: ng.IQService, oidcService: OidcService): ng.IDirective => ({
restrict: 'E',
scope: {},
template: '<div class="user-session-avatar" id="user-session-avatar"></div>',
link(_, element) {
$q.all([
// this gets information about the user (can be the JWT parsed directly or whatever)
// and also gets the URL to the Authority (which means to Sequel Authentication)
oidcService.getAuthority(),
oidcService.getUser(),
]).then(([authentication, user]) => {
// do not render anything if there is no user, for example, while loggin in
if (!user) return;
render(
(
<UserSessionAvatar
user={{
userName: user.profile.sub,
firstName: user.profile.given_name,
lastName: user.profile.family_name,
email: user.profile.email,
}}
urls={{
authentication,
async logOut() {
await oidcService.logOut();
},
async renewSsoCookie() {
await oidcService.renewSsoCookie();
},
async refreshSession() {
await oidcService.refreshSession();
},
}}
loggingEnabled={process.env.NODE_ENV === 'development'}
/>
), element[0],
);
});
},
});
UserSessionAvatarDirective.$inject = ['$q', 'oidcService'];
export default UserSessionAvatarDirective;
Register the directive in the module and use it:
ngModule.directive('userSessionAvatar', UserSessionAvatar)
<div class="super-navbar">
<!-- ... -->
<user-session-avatar></user-session-avatar>
</div>
Angular¶
Integration with angular is similar to angular.js but it requires some steps in order to bridge between both.
First ensure to have configured "jsx": "react-jsx"
in the tsconfig.json
file. And do not forget to install @types/react
and @types/react-dom
.
Then create a new component, but rename the .component.ts
to .component.tsx
.
Using the @ViewChild
annotation will bridge the react component into angular:
// user-session-avatar.component.tsx
import {
Component,
ViewContainerRef,
AfterViewInit,
ViewChild
} from "@angular/core";
import { render } from "react-dom";
import { forkJoin } from 'rxjs';
import type OidcService from '.../oidc.service'; // your authentication service
@Component({
selector: "app-user-session-avatar",
templateUrl: "./user-session-avatar.component.html",
styleUrls: []
})
export class UserSessionAvatarComponent implements AfterViewInit {
@ViewChild("container")
container!: { nativeElement: HTMLDivElement };
constructor(private readonly oidcService: OidcService) {}
ngAfterViewInit(): void {
this.renderComponent();
}
private renderComponent(): void {
forkJoin(
// this gets information about the user (can be the JWT parsed directly or whatever)
// and also gets the URL to the Authority (which means to Sequel Authentication)
this.oidcService.getAuthority(),
this.oidcService.getUser(),
).subscribe(([authentication, user]) => {
// do not render anything if there is no user, for example, while loggin in
if (!user) return;
render(
(
<UserSessionAvatar
user={{
userName: user.profile.sub,
firstName: user.profile.given_name,
lastName: user.profile.family_name,
email: user.profile.email,
}}
urls={{
authentication,
logOut: async () => {
await this.oidcService.logOut();
},
renewSsoCookie: async () => {
await this.oidcService.renewSsoCookie();
},
refreshSession: async() => {
await this.oidcService.refreshSession();
},
}}
/>
),
this.container.nativeElement,
);
})
}
}
<!-- user-session-avatar.component.html -->
<div class="user-session-avatar" #container></div>
React¶
Just use the component wherever you want to call it. Recommended to wrap the User Session Avatar inside another component to keep together the mappings and callbacks.
If want an example, checkout Administration's code.
Plain JS¶
Component documentation talks about this integration, and there are even a bundle for it. But it is deprecated and some time in the future will be removed. Do not rely on this build!
Appendix: Configure Nexus Registry¶
Near the package.json
write the following contents inside .npmrc
:
@sequel:registry=https://nexus.office.sbs/repository/npm/
strict-ssl=false