OpenID Connect (client side)
Oneki.js supports the Open ID Connect (OIDC) authorization code flow where the authorization code is exchanged for an access token via a server. This is the most common and secure way to retrieve the access token
In settings.js, when the "idp type" is "oidc_server", Oneki.js implements the following scenario:
To authenticate against an OpenID Connect Identity Provider (OIDC IDP), you have to create four pages/routes:
- login: this page is displayed following a click on a link or a redirect following a 401 HTTP Error
 - login callback: this route is called by the OIDC IDP (e.g: Google) after a successfull authentication
 - logout: this page is displayed following a click on a logout link or if there is no activity for x minutes (configurable via settings)
 - logout callback: this route is called by the OIDC IDP after a successfull logout
 
The code is the same for a NextJS App or a Create React App
- Login
 - Login Callback
 - Logout
 - Logout Callback
 
import React from "react";
import { useLoginService } from "onekijs";
export default React.memo(() => {
  const idpName = 'google';
  const options = {};
  const [error] = useLoginService(idpName, options);
  if (error) {
    return <div>{error.payload.message} <span onClick={() => error.remove()}>X</span></div>
  }
  return null;
}
Parameters
Inputs
// [Optional] the name of the IDP used for the login -- defaults to "default"
idpName: string
// [Optional] options object -- defaults to {}
options: {
  // a callback function triggered when an error is thrown -- defaults to send error on topic "login-error"
  onError: func
}
Outputs
error: {
  payload: {
    // description of the error
    message: string,
    // code of the error
    code: string,
  }
  
  // remove the error
  remove: func
}
import React from "react";
import { useLoginCallbackService } from "onekijs";
export default React.memo(() => {
  const idpName = 'google';
  const options = {};
  const [error] = useLoginCallbackService(idpName,options);
  if (error) {
    return <div>{error.payload.message} <span onClick={() => error.remove()}>X</span></div>
  }
  return null;
}
Parameters
Inputs
// [Optional] the name of the IDP used for the login -- defaults to "default"
idpName: string
// [Optional] options object -- defaults to {}
options: {
  // a callback function triggered when an the login is successfull -- The default redirects the user from the calling page
  onSuccess: func
  // a callback function triggered when an error is thrown -- defaults to send error on topic "login-error"
  onError: func
}
Outputs
error: {
  payload: {
    // description of the error
    message: string,
    // code of the error
    code: string,
  }
  
  // remove the error
  remove: func
}
import React from "react";
import { useLogoutService } from "onekijs";
export default React.memo(() => {
  const options = {};
  const [error] = useLogoutService(options);
  if (error) {
    return <div>{error.payload.message} <span onClick={() => error.remove()}>X</span></div>
  }
  return null;
}
Parameters
Inputs
// [Optional] options object -- defaults to {}
options: {
  // a callback function triggered when an error is thrown -- defaults to send error on topic "logout-error"
  onError: func
}
Outputs
error: {
  payload: {
    // description of the error
    message: string,
    // code of the error
    code: string,
  }
  
  // remove the error
  remove: func
}
import React from "react";
import { useLoginCallbackService } from "onekijs";
export default React.memo(() => {
  const options = {};
  const [error] = useLogoutCallbackService(options);
  if (error) {
    return <div>{error.payload.message} <span onClick={() => error.remove()}>X</span></div>
  }
  return null;
}
Parameters
Inputs
// [Optional] options object -- defaults to {}
options: {
  // a callback function triggered when an the logout is successfull -- The default redirects the user to the home page
  onSuccess: func
  // a callback function triggered when an error is thrown -- defaults to send error on topic "logout-error"
  onError: func
}
Outputs
error: {
  payload: {
    // description of the error
    message: string,
    // code of the error
    code: string,
  }
  
  // remove the error
  remove: func
}
Configuration
useLoginService, useLoginCallbackService, useLogoutService, useLogoutCallbackService are fully configured in settings.js
The configuration must be defined under the key "idp/:idpName". For example, if idpName=google, the config must look like this:
const settings = {
  idp: {
    google: {
      type: "oidc_server",
      ...
    }
  }
}
Mandatory attributes
| Key | Type | Description | 
|---|---|---|
| authorizeEndpoint | string | function(context)  | Can be
  | 
| clientId | string | the client_id created on the IDP (identity provider) | 
| logoutEndpoint | string | function(context)  | Can be
  | 
| tokenEndpoint | string | function(grant_type, context)  | Can be
  | 
| type | string | must be "oidc_server" | 
| userinfoEndpoint | string | function (context)  | Can be:
  | 
Optional attributes
| Key | Type | Description | Default | 
|---|---|---|---|
| callback | function(response, context): [token,userInfo] | Callback called at the end of the authentication for extracting the token and the userInfo from the response.  Inputs 
 
  | null | 
| codeChallengeMethod | string | Method that was used to derive an authorization code challenge | S256 | 
| jwksEndpoint | string | function(token, context)  | jwksEndpoint is mandatory if validate = true. Can be 
  | null | 
| loginCallbackRoute | string | a relative or absolute URL called by the OIDC server after a successfull login. | [loginRoute]/callback | 
| logoutCallbackRoute | string | a relative or absolute URL called by the OIDC server after a successfull logout. Should be used to remove the cookie on the server side | [logoutRoute]/callback | 
| pkce | boolean | flag to indicate if the PKCE extension is applied. Recommended | true | 
| nonce | boolean | flag to indicate if the nonce in the id_token is validated on the client side. Should be done on the server side | false | 
| postLoginRedirectKey | string | When calling the authorize endpoint, postLoginRedirectKey represents the name of the parameter to indicate the redirect URI | redirect_uri | 
| postLogoutRedirectKey | string | When calling the logout endpoint, postLoginRedirectKey represents the name of the parameter to indicate the redirect URI | post_logout_redirect_uri | 
| responseType | string | only code is supported right now | code | 
| scope | string | the value of the parameter "scope" sent to the authorize endpoint. Should generally be redefined | openid | 
| state | boolean | flag to indicate if the javascript client send a state to the IDP. Recommended for mitigating attacks | true | 
| validate | boolean | flag to indicate if the id_token and the access_token are validated. Should generally be done on the server side | false | 
Configuration example
const settings = {
  idp: {
    google: {
      type: 'oidc_server', 
      clientId: '1eb5cq6p7d8dm8g4q9jk6qdve5', // id given by Google              
      authorizeEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth', // URL given by Google. Will be called by the client
      tokenEndpoint: '/api/oauth2/token',   // URL of a service exposed by your server that exchanges the authorization code for an access token by calling the Google /token endpoint
      userinfoEndpoint: '/api/oauth2/userinfo', // URL of a service exposed by your server that returns the details about the logged-in user
      logoutEndpoint: '/api/oauth2/logout', // URL exposed by your server which call the IDP logout URL and then removes the cookie
      scope: 'openid email profile', // ask to Google the profile and the email of the user
    }
  }
}