Login
Login components include React components, context and hooks for handling user authorisation, api tokens and authorized requests.
Introduction
HDS Login system is built on modular vanilla JavaScript and can handle every aspect of user authorization. It can be used with or without React. React version also includes a context, components and hooks.
Current modules can handle
- User authorisation with any OIDC server.
- Exchange of user tokens to API tokens.
- Creation of ApolloClient with auto-appended api tokens in query headers.
- GraphQL queries with auto-appended api tokens in the query headers.
- Fetch requests with auto-appended api tokens in the request headers.
- Active session polling if user session is ended in other browsers or server side.
- Addition of custom modules.
Modules interact with emitted signals that can be listened like native events. React is not a requirement, but currently, no vanilla JavaScript UI components exist, but modules can be controlled with any interactive elements.
Implementation requires an OIDC provider, which is a server for user authorization. The City of Helsinki uses Helsinki Profile, but HDS login components can be used with any compatible OIDC provider. Read more about OpenID Connect (OIDC).
In the OIDC login process, the browser window is redirected to the OIDC provider. Authentication is fully handled by the server. That is why HDS does not provide login or registration forms.
When the user has been authenticated, the OIDC server redirects back to the service. HDS provides components to handle the authentication process initiation and responses.
For Login UI components see Header.Login on Header component page. For more information on how HDS Login and Header.Login components are meant to work together see Login pattern page.
Requirements
Your service must be registered with an OIDC provider, like Helsinki Profile.
To use the OIDC provider with login components, you need
- Client id.
- Authority.
- URL of the OIDC provider.
Important
The HDS Oidc client stores data in session storage for security reasons. Session storage is not shared across browser windows or tabs, so the user must log in separately for each window.
Silent session renewal requires a dedicated HTML file that redirects to the OIDC provider "silently" in an iframe.
Consents for storing data
The data of the authenticated user is stored in the session storage. Users must give consent to storing data in the session storage, just like cookie consents. You can use the ready-made consents in the common Helsinki cookies.
Example Usage
// Actual properties are omitted from this example to keep it simpleconst providerProperties = {...}const SayHelloIfUserExists = () => {const user = useAuthenticatedUser();if ( user ) {return <p>Hello, { user.name }!</p>} else {return (<><p>You are not logged in.</p><LoginButton errorText="Login failed. Try again!">Log in</LoginButton></>)}}<LoginProvider {...providerProperties}><SayHelloIfUserExists /></LoginProvider>
Components
HDS Login components include
- A React context that exposes user data and other modules to React hooks and components.
- Login buttons with error handling.
- A callback handler for parsing the authentication response.
- Wrappers that conditionally render their children depending on authentication status.
There is no component for logout. It is just a redirection link and any button can be used for it. No error handling is required.
Detailed documentation can be found in the components section of the Usage page.
Hooks
HDS Login hooks enable to
- Check login status.
- Get user data.
- Add listeners.
- Login and logout.
- Get API tokens.
- Use API tokens in requests.
- Get modules.
Detailed documentation is in the hooks section of the Usage page.
Modules
There are five modules to handle different scenarios:
- Oidc client for user data.
- Api tokens client for acquiring backend tokens.
- Session poller for checking if the user's session is still valid at the Oidc provider.
- ApolloClient module to provide the client and auto-append api tokens to queries.
- GraphQL module for fetching data from a graphQL server. Fetching can be automatically
- TokenizedFetch module for making fetch calls to a server. Fetching is automatically linked to the Api Tokens client.
If a module is not needed, it can be dropped with settings. Custom modules can also be added. All modules can be used without React and without each other. But a valid user object is required to get API tokens and poll the session.
Modules emit signals to communicate with other modules. For example, the Api tokens client module refreshes its tokens when user tokens in the Oidc client module have been refreshed.
Detailed information is in the modules section of the Usage page.
Oidc client module
This module handles the login process and parses tokens from the login response. It also renews tokens and handles token storage and removal. Logout is also handled by this module.
Api tokens client module
This module exchanges the user's tokens for API tokens. API tokens are used for querying data from backend servers. The module renews the tokens if the user's tokens change.
Session poller module
This module polls the user's session from the Oidc provider and signals an error if polling returns an unauthorized response. If you have logged in with the same user in multiple browser windows, this module detects when the user is logged out in any browser window.
ApolloClient module
This module creates a client with middleware and provides the client to all modules and also to all components in the Login Context including ApolloClient's hooks. The module can wait for api tokens and automatically append them to headers. When ApolloClient's own hooks are used, the ApolloContext is not automatically created unless the LoginProviderWithApolloContext component is used. The context can also be created manually by picking the ApolloClient with hooks. The ApolloClient is not automatically added, but it's setup is simple.
GraphQL module
This module was added to make it easier to use the login system with authenticated graphQL queries. The GraphQL module waits for api tokens and automatically picks a token and uses it in queries. The GraphQL module is not automatically added, but it's setup is simple.
TokenizedFetch module
This module was added to make it easier to use the login system with authenticated fetch
calls. The TokenizedFetch module waits for api tokens and assigns headers to the request headers.
The TokenizedFetch module is not automatically added, but it's setup is simple.
Custom modules
Other modules can be added. Detailed information is in the custom modules section.
Signals
Modules communicate with signals. A module emits signals and listener functions are triggered by them. Listeners can be added by modules, components or plain Javascript. Components can listen to signals with hooks.
The signal emitter is called a Beacon. Usually, only error signals should be monitored. Data updates are handled automatically.
Detailed information is in the signals section of the Usage page.
Common settings for localhost
Every service must have its own client_id
and scope
, but these settings can be used for testing.
They only work in http://localhost:3000
. Make sure you have redirect_uri
, silent_redirect_uri
and post_logout_redirect_uri
registered at the OIDC server.
const loginProviderProps: LoginProviderProps = {userManagerSettings: {authority: 'https://tunnistamo.dev.hel.ninja/',client_id: 'exampleapp-ui-dev',scope: 'openid profile email https://api.hel.fi/auth/helsinkiprofiledev https://api.hel.fi/auth/exampleappdev',redirect_uri: `YOUR_REGISTERED_REDIRECT_URL`,silent_redirect_uri: `URL_TO_YOUR_REGISTERED_LOCAL_SILENT_RENEW.HTML`,post_logout_redirect_uri: `YOUR_REGISTERED_LOGOUT_URL`,},apiTokensClientSettings: { url: 'https://tunnistamo.dev.hel.ninja/api-tokens/' },sessionPollerSettings: { pollIntervalInMs: 10000 },};
If you are using Helsinki Profile, then use these settings:
const loginProviderProps: LoginProviderProps = {userManagerSettings: {authority: 'https://tunnistus.dev.hel.ninja/auth/realms/helsinki-tunnistus',client_id: 'exampleapp-ui-dev',scope: 'openid profile',redirect_uri: `YOUR_REGISTERED_REDIRECT_URL`,silent_redirect_uri: `URL_TO_YOUR_REGISTERED_LOCAL_SILENT_RENEW.HTML`,post_logout_redirect_uri: `YOUR_REGISTERED_LOGOUT_URL`,},apiTokensClientSettings: {url: 'https://tunnistus.dev.hel.ninja/auth/realms/helsinki-tunnistus/protocol/openid-connect/token',queryProps: {grantType: 'urn:ietf:params:oauth:grant-type:uma-ticket',permission: '#access',},audiences: ['exampleapp-api-dev', 'profile-api-dev'],},sessionPollerSettings: { pollIntervalInMs: 10000 },};