API Documentation
Initialize the client
The library exposes two factory functions – createOauthClient for basic oAuth with Authorization Code Grant and the PKCE extension and createOidcClient if you want to leverage OIDC (also with code flow + PCKE).
createOauthClient
function createOauthClient(configArg: OauthClientConfig): OauthClient
Basic example:
import { createOauthClient } from 'lionel-oauth-client'
const oAuthClient = createOauthClient({
issuer: 'https://sso.example.com',
clientId: 'my_client_id',
redirectUri: 'https://example.com/oauth-callback.html',
scopes: ['api']
})
createOidcClient
function createOidcClient(configArg: OauthClientConfig): OauthClient
Basic example:
import { createOidcClient } from 'lionel-oauth-client'
const oAuthClient = createOidcClient({
issuer: 'https://sso.example.com',
clientId: 'my_client_id',
redirectUri: 'https://example.com/oauth-callback.html',
scopes: ['api', 'profile'] // Note: 'openid' scope will be added automatically
})
Both factory functions take an OauthClientConfig
object as arguments, but they set default options on that object differently. When you create a client you should be consistent in what config options you use so they are always the same for the same client. See the Configuration section below for a complete list of options.
The factory functions also return the same type of object, of the type OauthClient
:
interface OauthClient {
signIn: (options: SignInOptions) => Promise<void>
signInSilently: (
options: SignInOptions
) => Promise<HandleCallbackResponse | null>
handleCallback: () => Promise<HandleCallbackResponse | null>
getConfig: () => OauthClientConfig
getAccessToken: () => string | null
removeAccessToken: () => void
subscribe: EventSubscribeFn
unsubscribe: EventSubscribeFn
getUser: () => Promise<User | null>
getUserInfo: () => Promise<User | null>
removeUser: () => void
signOut: (options: SignOutOptions) => Promise<void>
}
See the Client Methods section below for a specification of the methods of the OauthClient
.
Configuration
Configuration of the client is handled by the config options you send as a OauthClientConfig
object into the factory functions createOauthClient
and createOidcClient
.
interface OauthClientConfig {
issuer: string
clientId: string
redirectUri: string
scopes?: string[]
authorizationEndpoint?: string
tokenEndpoint?: string
tokenStorage?: StorageModuleType
tokenLeewaySeconds?: number
authenticationMaxAgeSeconds?: number
signInSilentlyTimeoutSeconds?: number
autoRenewToken?: boolean
responseMode?: ResponseMode
metaData?: MetaData
useNonce?: boolean
useMetaDataDiscovery?: boolean
useUserInfoEndpoint?: boolean
display?: Display
uiLocales?: string[]
acrValues?: string[]
debug?: boolean
}
Below is a complete list and definitions of these options:
OauthClientConfig.issuer
Required string
. The url of the oAuth/OIDC issuer (provider).
OauthClientConfig.clientId
Required string
. The client_id of the issuer client that you want to use.
OauthClientConfig.redirectUri
Required string
. Absolute uri where you handle the callback from your issuer. This is where the issuer will send users after authorization.
OauthClientConfig.scopes
Optional array
of string
. The scope that you want to request from the issuer. When you use createOidcClient
to create your client openid
will always be added to scopes
.
OauthClientConfig.authorizationEndpoint
Optional string
. The endpoint at the issuer for the authorization request endpoint. Defaults to /authorize
, but this property is not used if you use Open ID Discovery, which is enabled by default if you use createOidcClient
to create your client.
OauthClientConfig.tokenEndpoint
Optional string
. The endpoint at the issuer for the token request endpoint. Defaults to /token
, but this property is not used if you use Open ID Discovery, which is enabled by default if you use createOidcClient
to create your client.
OauthClientConfig.tokenStorage
Optional string
(of type StorageModuleType
). Can be local
or session
, defaults to session
. Sets if tokens and other client data is stored in the browser's sessionStorage
or localStorage
.
OauthClientConfig.tokenLeewaySeconds
Optional number
. Defaults to 60. The number of seconds to allow the current time to deviate when validating expires_in
in the token response and nbf
and exp
attributes of jwt tokens.
OauthClientConfig.authenticationMaxAgeSeconds
Optional number
. The maximum allowable elapsed time in seconds since the last time the end-user was actively authenticated at the issuer.
OauthClientConfig.signInSilentlyTimeoutSeconds
Optional number
. Defaults to 10. Number of seconds to wait for the silent sign in to return before assuming it has failed or timed out.
OauthClientConfig.autoRenewToken
Optional boolean
. Defaults to true
. This specifies if a silent signin should be performed before access tokens are expired and removed from the client. The tokenWillExpireSeconds
option will decide how far in advance this is done.
OauthClientConfig.tokenWillExpireSeconds
Optional number
. Defaults to 60
. This specifies how long before the token expiry the tokenWillExpire
event will be published. This also controls how far in advance tokens will be auto renewed before they expire.
OauthClientConfig.responseMode
Optional string
(of type ResponseMode
). Can be fragment
or query
. This specifies if parameters from the issuer will be send back as a url hash or query variables to the callback page. If not specified, the issuer's default will be used.
OauthClientConfig.metaData
Optional object
(of type MetaData
). If you do not use Open ID Discovery you can specify the OIDC meta data here. If you use discovery you can also use this option to override specific attributes in the discovery meta data.
Type definition:
interface MetaData {
issuer: string
authorization_endpoint: string
token_endpoint: string
userinfo_endpoint?: string
jwks_uri: string
registration_endpoint?: string
scopes_supported?: string[]
response_types_supported: string[]
response_modes_supported?: string[]
grant_types_supported?: string[]
acr_values_supported?: string[]
subject_types_supported: string[]
id_token_signing_alg_values_supported: string[]
id_token_encryption_alg_values_supported?: string[]
id_token_encryption_enc_values_supported?: string[]
userinfo_signing_alg_values_supported?: string[]
userinfo_encryption_alg_values_supported?: string[]
userinfo_encryption_enc_values_supported?: string[]
request_object_signing_alg_values_supported?: string[]
request_object_encryption_alg_values_supported?: string[]
request_object_encryption_enc_values_supported?: string[]
token_endpoint_auth_methods_supported?: string[]
token_endpoint_auth_signing_alg_values_supported?: string[]
display_values_supported?: string[]
claim_types_supported?: string[]
claims_supported?: string[]
service_documentation?: string
claims_locales_supported?: string[]
ui_locales_supported?: string[]
claims_parameter_supported?: boolean
request_parameter_supported?: boolean
request_uri_parameter_supported?: boolean
require_request_uri_registration?: boolean
op_policy_uri?: string
op_tos_uri?: string
check_session_iframe?: string
end_session_endpoint?: string
[key: string]: any
}
OauthClientConfig.useNonce
Optional boolean
. Defaults to false
if you use createOauthClient
and true
if you use createOidcClient
to create your client. Specifies if a nonce should be included in the authorization request to the issuer. If useNonce
is true the client will require the id token to include the nonce and validate it when the callback is handled.
OauthClientConfig.useMetaDataDiscovery
Optional boolean
. Defaults to false
if you use createOauthClient
and true
if you use createOidcClient
to create your client. Specifies if the client should look up issuer meta data through Open ID Discovery.
OauthClientConfig.useUserInfoEndpoint
Optional boolean
. Defaults to false
if you use createOauthClient
and true
if you use createOidcClient
to create your client. Specifies if the client should request user info from the issuer's user info endpoint.
OauthClientConfig.display
Optional string
(of type Display
). Can be page
, popup
, touch
or wap
, defaults to page
. Specifies how the issuer should display the authentication and consent user interface pages to the end-user.
OauthClientConfig.uiLocales
Optional array
of string
. End-user's preferred languages for the user interface at the issuer (e.g. ['sv-SE', 'en']
). Ordered by preference. The issuer should not throw an error if it does not support these, this is only a declaration of preference.
OauthClientConfig.acrValues
Optional array
of string
. Specifies the acr_values that the issuer is being requested to use for processing this authentication request, with the values appearing in order of preference.
OauthClientConfig.debug
Optional boolean
. Defaults to false. If debug
is true the client will output verbose logging in the browser console.
Client Methods
When you have created a client, these are the methods on it that you can call:
handleCallback
async function handleCallback() => Promise<HandleCallbackResponse | null>
Process the response from the issuer. This is done on the redirect uri you have specified as redirectUri
.
Basic example:
try {
await oAuthClient.handleCallback()
location.assign('/') // Set where you want to redirect the user after successful signin
} catch (error) {
console.error(error)
}
If the signin in the client fails the promise that the method returns will be rejected. If the user is successfully signed in the promise will resolve with an object of the type HandleCallbackResponse
:
interface TokenResponse {
accessToken: string
idToken?: string
expires: number
}
interface HandleCallbackResponse {
tokenResponse: TokenResponse
callbackType: CallbackType
user: User | null
}
signIn
async function signIn(options: SignInOptions = {}): Promise<void>
This performs redirect of the current window to the authorization endpoint of the issuer. The method returns a Promise in order to enable error handling of the generating of the redirect.
Basic example:
oAuthClient.signIn()
The signIn
methods take an optional argument of an object of the type SignInOptions
:
interface SignInOptions {
idTokenHint?: string
loginHint?: string
display?: string
prompts?: Prompt[]
nonce?: string
}
Below is a complete list and definitions of these options:
SignInOptions.idTokenHint
Optional string
. Id token previously issued by the issuer being passed as a hint about the end-user's current or past authenticated session with the client.
SignInOptions.loginHint
Optional string
. This is a hint to the issuer about what identifier the end-user might use to log in (if necessary). For instance if you first ask the end-user for their e-mail address (or other identifier) and then want to pass that value as a hint to the issuer.
SignInOptions.display
Optional string
(of type Display
). Can be page
, popup
, touch
or wap
, defaults to the display
option of the client. Specifies how the issuer should display the authentication and consent user interface pages to the end-user.
SignInOptions.prompts
Optional array of string
(of type Prompt
). Can include none
, login
, consent
or select_account
. Specifies whether the issuer prompts the end-user for reauthentication and consent.
SignInOptions.nonce
Optional string
. Here you can provide your own nonce to send to the issuer. If you leave this empty the client will generate a nonce for you (if useNonce
is true
).
signInSilently
async function signInSilently(
options: SignInOptions = {}
): Promise<HandleCallbackResponse | null>
This method sign a user in silently, that is without the end user being redirected to the issuer. This will perform an authentication in a hidden iframe, and if a user is signed in at the issuer the user will be signed in in the client.
Basic example:
try {
const signInResponse = await oAuthClient.signInSilently()
if (!response.user) {
alert('Not signed in')
return
}
location.reload()
} catch (error) {
alert(error)
}
The method's argument is the same as for signIn
, but the prompts
option will always be ['none']
.
If the method returns a Promise that resolves with a HandleCallbackResponse
with a user
attribute (or a tokenResponse.accessToken
attribute if you do not use OIDC) the user was signed in at the issuer and is now signed in at the provider.
getAccessToken
function getAccessToken(): string | null
Get the access token of user that is authenticated in the client. If there is no token the method will return null (and not throw an error).
Basic example:
const accessToken = oAuthClient.getAccessToken()
getAccessTokenExpires
function getAccessTokenExpires(): number
Get the expires timestamp of the access token in seconds from January 1st, 1970 at UTC. The tokens and the user will be removed from storage at this time if the tokens are not renewed before then.
Basic example:
const accessTokenExpires = oAuthClient.accessTokenExpires()
removeAccessToken
function removeAccessToken(): void
Removes the access token (effectively a client side sign out when not using openid scope). This will not sign the user out at the issuer.
Basic example:
await oAuthClient.removeAccessToken()
getUser
async function getUser(): Promise<User | null>
Get the decoded user claims from id_token and from the latest UserInfo response if a UserInfo request has been made. If there is no user the Promise that the method returns will resolve with null
.
Basic example:
let user
try {
user = await oAuthClient.getUser()
} catch (error) {
console.error(error)
}
What the user object looks like will depend on what claims the issuer returns. The type definition look like this:
removeUser
function removeUser(): void
Removes the access token and id token (effectively a client side sign out). This will not sign the user out at the issuer.
Basic example:
oAuthClient.removeUser()
signOut
async function signOut(options: SignOutOptions): Promise<void>
Signs out user both in client and in issuer (and will redirect the user to the issuer). This requires end_session_endpoint in meta data (or in the issuer's discovery meta data).
Basic example:
oAuthClient.signOut()
The signOut
methods take an optional argument of an object of the type SignOutOptions
:
interface SignOutOptions {
postLogoutRedirectUri?: string
useIdTokenHint?: boolean
}
Below is a complete list and definitions of these options:
SignOutOptions.postLogoutRedirectUri
Optional string
. Absolute uri where the issuer should redirect the end-user after signing them out. This requires an id token hint to be sent, so it is only possible if you use OIDC.
SignOutOptions.useIdTokenHint
Optional boolean
. Defaults to false
but if you provide a postLogoutRedirectUri
this will be true, since the open id specification requires this. This option specifies if the current id token in the client should be passed as a hint about the end-user's current or past authenticated session with the client.
Events
The client publishes events when things that has to do with authentication happens that you can subscribe to.
Subscribe to an event to trigger a function in response:
/** Supported event types: "tokenLoaded", "tokenUnloaded", "userLoaded", "userUnloaded", "tokenWillExpire", "tokenDidExpire" */
oAuthClient.subscribe('tokenLoaded', () =>
console.log('An access token was loaded')
)
To unsubscribe from an event, you must provide the same function that was passed to oAuthClient.subscribe
:
/** Supported event types: "tokenLoaded", "tokenUnloaded", "userLoaded", "userUnloaded", "tokenWillExpire", "tokenDidExpire" */
oAuthClient.unsubscribe('tokenLoaded', () =>
console.log('An access token was loaded')
)
The events that you can subscribe on are:
tokenLoaded
This event is published when an access token is loaded in the client, it can be either when it is retreived from the callback response or when it is loaded from the token storage in the browser.
The payload of the event is the access token:
function exampleTokenLoadedListener(accessToken: string): void
tokenUnloaded
This event is published when an access token is unloaded in the client, it can be either after it has been expired or when it is removed with any of the methods removeAccessToken
, removeUser
or signOut
.
The event has no payload:
function exampleTokenUnloadedListener(): void
userLoaded
This event is published when a user is loaded in the client, it can be either when it is retreived from the callback response or when it is loaded from the token storage in the browser.
The payload of the event is the user:
function exampleUserLoadedListener(user: User): void
userUnloaded
This event is published when a user is unloaded in the client, it can be either after the access token has been expired or when the user is removed with any of the methods removeUser
or signOut
.
The event has no payload:
function exampleUserUnloadedListener(): void
tokenWillExpire (coming soon)
This event is published before the access token in the client will expire.
The event has no payload:
function exampleTokenWillExpireListener(): void
tokenDidExpire (coming soon)
This event is published after the access token in the client has expired.
The event has no payload:
function exampleTokenDidExpireListener(): void