@axinom/mosaic-user-auth library
Introduction
@axinom/mosaic-user-auth
is a React library that wraps the core
functionality in the User Service that is related to frontend
end-user applications. Developers can use the methods provided by
this library to perform all end-user authenticated operations
such as signing in, signing out, access token handling etc.
UserServiceProvider
UserServiceProvider is a React Provider which has 3 properties. It provides
the User Service Client which can be retrieved using the useUserService
hook.
userAuthConfig
- Configuration for the User Service Auth API. This is an object ofUserAuthConfig
type.userServiceConfig
- Configuration for the User Service GraphQL API. This is an object ofUserServiceConfig
type.tokenRenewalMethod
- Token Renewal method the application want to use. This is a value fromTokenRenewalMethod
enumeration.
UserAuthConfig
interface UserAuthConfig {
userAuthEndpointUrl: string;
tenantId: string;
environmentId: string;
applicationId: string;
}
Property | Description |
---|---|
userAuthEndpointUrl | URL of the User Service authentication endpoint. |
tenantId | The tenant ID connected to the end-user application. This is the tenant which the User Service Application is registered against. |
environmentId | The environment ID connected to the end-user application. This is the environment which the User Service Application is registered against. |
applicationId | The ID of the Application created in the User Service configuration. |
UserServiceConfig
interface UserAuthConfig {
userServiceEndpointUrl: string;
}
Property | Description |
---|---|
userServiceEndpointUrl | URL of the User Service GraphQL endpoint. |
TokenRenewalMethod
Value | Description |
---|---|
PRE_EMPTIVE | The token is continuously renewed just before expiry. A TokenChangedCallback can be registered using addTokenChangedHandler method to get notified when the token changes. |
ON_DEMAND | The token is renewed only if needed upon calling getToken method. |
Usage
The UserServiceProvider should be used as a context provider for the react app, at the top of the component hierarchy. This way we can ensure that all child components will have access to the UserServiceClient. Ideally, these properties can be retrieved through environment variables.
const userAuthConfig = {
userAuthEndpointUrl: 'https://id.ottstream.com',
tenantId: 'ace73f47-b654-43e3-bc23-a7ba83c6ea63',
environmentId: '559d0282-2e64-430c-8c4d-93f1777bba07'
applicationId: 'd5091350-4868-4efa-b508-f7438d910a70'
}
const userServiceConfig = {
userServiceEndpointUrl = 'https://user.service.eu.axinom.net'
}
<UserServiceProvider
userAuthConfig={userAuthConfig}
userServiceConfig={userServiceConfig}
tokenRenewalMethod={TokenRenewalMethod.PRE_EMPTIVE}
>
<App />
</UserServiceProvider>
UserServiceClient
UserServiceClient
is an object instance created through
the UserServiceProvider which provides
a set of methods to perform tasks related to the User Service
such as sign in, sign out, create user profile etc.
The instance created through the UserServiceProvider
can be
retrieved through the hook useUserService
.
Interfaces
The library makes use of the following interfaces to structure data in its methods.
Interface Name | Description |
---|---|
UserAuthConfig | Configuration for the user service auth API. |
UserServiceConfig | Configuration for the user service API. |
UserToken | Represents the information in a User Token. |
TokenResponse | Response for a getToken request. |
SignInRequest | Represents the information required to perform a username/password Sign In flow. |
UserSignUpRequest | Represents the information required for a new user sign up. |
CheckUserSignUpOtpRequest | Represents information required to check if a User Sign Up OTP is valid. |
CompleteUserSignUpRequest | Represents the information required to verify a new user sign up. |
CheckPasswordResetOtpRequest | Represents information required to check if a Password Reset OTP is valid. |
CheckPasswordResetOtpRequest | Represents the require information for Complete Password Reset request. |
AuthenticateEndUserApplicationRequest | Represents the information required to authenticate an End-User Application. |
EndUserApplicationToken | Represents an End-User Application Access Token. |
AuthenticateEndUserApplicationResponse | Response for a authenticateEndUserApplication request. |
UserAuthConfig
UserAuthConfig
interface holds the configuration for the User Service Auth API.
interface UserAuthConfig {
userAuthEndpointUrl: string;
tenantId: string;
environmentId: string;
applicationId: string;
}
UserServiceConfig
UserServiceConfig
interface holds the configuration for the User Service API.
interface UserServiceConfig {
userServiceEndpointUrl: string;
}
UserToken
UserToken
interface holds the information related to a User Token that is
returned by the User Service Auth API.
interface UserToken {
tenantId: string;
environmentId: string;
applicationId: string;
userId: string;
profileId: string;
email: string | null;
name: string | null;
extensions?: unknown;
accessToken: string;
expiresInSeconds: number;
}
UserProfile
UserProfile
interface contains information related to a User Profile.
interface UserProfile {
id: string;
displayName: string;
profilePictureUrl?: string;
profileData?: unknown;
defaultProfile: boolean;
}
TokenResponse
TokenResponse
interface stores the information that will be returned
by a call to getToken method.
interface TokenResponse {
code: 'SUCCESS' | 'ERROR';
message?: string;
userToken?: UserToken;
userProfile?: UserProfile;
/**
* This will indicate the next automatic token renewal timestamp when the
* `PRE_EMPTIVE` token renewal method is configured on the `UserServiceProvider`.
*
* For `ON_DEMAND` token renewal method, this value can be dismissed.
*/
nextTokenRenewalAt?: Date;
}
SignInRequest
SignInRequest
interface represents the information required by the
signIn method to perform a Sign In request using the
username/password Sign In flow.
interface SignInRequest {
email: string;
password: string;
}
UserSignUpRequest
UserSignUpRequest
interface represents the information required by the
initiateUserSignUp method which will start the user sign
up process.
interface UserSignUpRequest {
email: string;
password: string;
}
CheckUserSignUpOtpRequest
CheckUserSignUpOtpRequest
interface represents the information required
by checkUserSignUpOTP method which will check if a
given User Sign Up OTP is valid.
interface CheckUserSignUpOtpRequest {
signUpOtp: string;
}
CompleteUserSignUpRequest
CompleteUserSignUpRequest
interface represents the information required
by completeUserSignUp method which will complete the
User Sign Up flow.
interface CompleteUserSignUpRequest {
signUpOtp: string;
password?: string;
}
CheckPasswordResetOtpRequest
CheckPasswordResetOtpRequest
interface represents the information required
by checkResetPasswordOTP method which will check
if a given Reset Password OTP is valid.
interface CheckPasswordResetOtpRequest {
resetOtp: string;
}
CompletePasswordResetRequest
CompletePasswordResetRequest
interface represents the information required by
completeResetPassword method which will complete the
Reset Password flow.
interface CompletePasswordResetRequest {
resetOtp: string;
newPassword: string;
}
AuthenticateEndUserApplicationRequest
AuthenticateEndUserApplicationRequest
interface represents the information required
by authenticateEndUserApplication method to
authenticate an end-user application with User Service.
interface AuthenticateEndUserApplicationRequest {
tenantId: string;
environmentId: string;
applicationId: string;
applicationKey: string;
}
EndUserApplicationToken
EndUserApplicationToken
holds the information related to an End-User Application
Access Token.
interface EndUserApplicationToken {
accessToken: string;
expiresInSeconds: number;
tokenType: string;
}
AuthenticateEndUserApplicationResponse
AuthenticateEndUserApplicationResponse
interface represents the response
data returned by authenticateEndUserApplication
method.
interface AuthenticateEndUserApplicationResponse {
code: 'SUCCESS' | 'ERROR';
message?: string;
endUserApplicationToken?: EndUserApplicationToken;
}
Methods
The UserServiceClient provides the following methods.
Method Name | Description |
---|---|
getToken | Returns a access token. The method will ensure to avoid unnecessary API calls by caching valid tokens. It is not recommended to save the token for later use. When in need of a token, call this method to get a new token. |
addTokenChangedHandler | Adds an event handler that will be invoked whenever a new token response is loaded from the backend. |
removeTokenChangedHandler | Removes an event handler for the TokenChanged event |
getIdpConfigurations | Returns an array of IDP Configurations that are configured for the application. The authentication URL for IDPs will be sent along with this, which the frontend app should navigate to perform the sign in. This list will exclude connections for provider id AX_AUTH as it is used for user sign-up and sign-in flows. |
logoutUser | Logs out the user. |
initiateUserSignUp | Initiates the process to register a new user for the application. To use this flow, an IDP connection for the provider managed IDP AxAuth must be configured. |
checkUserSignUpOTP | Checks if a given User Sign-Up OTP Code is valid. |
completeUserSignUp | Completes a user sign up process using the AxAuth IDP.The user needs to input the OTP along with a password (if not provided earlier) to finish the process. |
signIn | Starts the Sign-In flow for signed up users using the AxAuth IDP configured for the application. This sign in is executed using username/password Sign In flow. |
initiateResetPassword | Initiates the process of resetting the password for a self signed up user through AxAuth. This will initiate the call to the webhook configured in AxAuth to send the generated OTP. |
checkResetPasswordOTP | Checks if a given Reset Password OTP Code is valid. |
completeResetPassword | Completes the password reset flow for a user registered using the AxAuth IDP. The user needs to input the OTP along with a new password to finish the process. |
setActiveProfile | Sets a given profile ID as the active profile. |
getUserProfile | Returns user profile details for a given ID. |
getUserProfiles | Returns all user profiles for a given user. |
createUserProfile | Creates a new user profile for a user. |
updateUserProfile | Update user profile for a given ID. |
deleteUserProfile | Deletes a user profile for a given ID. |
authenticateEndUserApplication | Authenticates an end-user application and returns an Application Token. This token can be used within the application to make requests to end-user facing APIs exposed by Mosaic Services. (i.e. query subscription plans from the Billing Service.) |
getToken
getToken
method can be used to fetch the user access token from User Service
after the authentication is completed. If a User Token Enrichment Webhook is
defined for the Application, that will be called at this point, and the returned
user access token will contain the additional information added under the extensions
property.
Usage
import { TokenResponse, useUserService } from '@axinom/mosaic-user-auth';
const {getToken} = useUserService();
const [tokenResponse, setTokenResponse] = useState<TokenResponse | null>(
null,
);
setTokenResponse(await getToken());
getToken
returns a TokenResponse object.
addTokenChangedHandler
addTokenChangeHandler
can be used as an event listener for the frontend
to be notified whenever a new token is loaded from User Service.
Usage
import { TokenResponse, useUserService } from '@axinom/mosaic-user-auth';
const {getToken, addTokenChangedHandler} = useUserService();
const [tokenResponse, setTokenResponse] = useState<TokenResponse | null>(
null,
);
useEffect(() => {
(async () => {
setTokenResponse(await getToken());
})();
}, [addTokenChangedHandler, getToken]);
Using addTokenChangeHandler
in the dependency list like above when calling
getToken from within a useEffect
block will make the getToken
method to
be called whenever the token is changed and refresh it.
removeTokenChangedHandler
removeTokenChangedHandler
can be used to remove the event handler from the
TokenChanged event.
Usage
import { TokenResponse, useUserService } from '@axinom/mosaic-user-auth';
const {getToken, removeTokenChangedHandler} = useUserService();
const [tokenResponse, setTokenResponse] = useState<TokenResponse | null>(
null,
);
useEffect(() => {
(async () => {
setTokenResponse(await getToken());
})();
}, [removeTokenChangedHandler, getToken]);
getIdpConfigurations
An end-user application may retrieve all the available IDP Connections by
calling getIdpConfigurations
method.
Usage
import { IdpConfiguration, useUserService } from '@axinom/mosaic-user-auth';
const { getIdpConfigurations } = useUserService();
const [idpConfigurations, setIDPConfigurations] = useState<
IdpConfiguration[]
>([]);
useEffect(() => {
(async () => {
const idpConfigs = await getIdpConfigurations(
`app.ottstream.com`,
);
setIDPConfigurations(idpConfigs);
})();
}, [getIdpConfigurations]);
logoutUser
When logoutUser
is called from an end-user application, it will
remove any authentication related cookies(AX_REFRESH_TOKEN) from
the browser and remove the user token from User Service backend.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { logoutUser } = useUserService();
await logoutUser();
logoutUser
can be ideally called from a onClick
event of Sign Out button.
initiateUserSignUp
The user sign up flow consists of two steps. First the application needs to
make an initiateUserSignUp
request, which will create a record with the
user’s email address and generate a Sign Up OTP.
initiateUserSignUp
returns a UserSignUpResponse object.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { initiateUserSignUp } = useUserService();
const signUpResponse = await initiateUserSignUp(`app.ottstream.com/signup`, {email, password});
checkUserSignUpOTP
After initiateUserSignUp is called, the AxAuth Service generates
Sign Up OTP for against the user’s email address. Frontend applications can use
checkUserSignUpOTP
method to check if any given OTP code is valid, before making
the call to completeUserSignUp method.
This is not a mandatory call, and can be done at the developer’s discretion to make the user experience more seamless.
checkUserSignUpOTP
returns a CheckUserSignUpOtpResponse
where the isOtpValid
property can be extracted from.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { checkUserSignUpOTP } = useUserService();
const { isOtpValid } = await checkUserSignUpOTP('app.ottstream.com', { signUpOtp });
completeUserSignUp
The second and final step of the user sign up flow is to call completeUserSignUp
method. This call takes the Sign Up OTP as an argument, and a password if a password
was not provided at the initiateUserSignUp stage. (If no password
was provided at either in the first step or this, an error will be raised.) This
call will mark the newly sign up user account as verified in the backend, and make
it available for future use.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { completeUserSignUp } = useUserService();
const completeUserSignUpResponse = await completeUserSignUp({signUpOtp, password});
signIn
The signIn
method must be used when a user that was registered through AxAuth
is signing in to the application.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { signIn } = useUserService();
const handlesSignIn = async(event: React.FormEvent<HTMLFormElement>): Promise<void> => {
event.preventDefault();
const signInResponse = await signIn({
email: email,
password: password
});
if (signInResponse.code === SignInResponseCode.SUCCESS) {
window.location.assign('/');
} else {
setError(`Unable to Sign In. ${signInResponse.details?.error ?? signInResponse.message}`)
}
}
The handleSignIn
method in the example could be called from the onClick
event of the Sign-In button.
initiateResetPassword
The application developers can use initiateResetPassword
method when implementing
password reset feature for AxAuth users. This is the first step of a two step process
where a Password Reset OTP would be generated against the user’s email.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { initiateResetPassword } = useUserService();
const initiatePasswordReset = async(event: React.FormEvent<HTMLFormElement>): Promise<void> => {
event.preventDefault();
const initiatePasswordResetResponse = await initiateResetPassword(`${ottstream_APP_BASE_URL}/reset-password`, email);
if (initiatePasswordResetResponse.code === PasswordResponseCode.SUCCESS) {
window.location.assign('/complete-reset-password');
} else {
setError(initiatePasswordResetResponse.message ?? 'Error resetting password.');
}
}
The initiatePasswordReset
method in the example could be called from the onClick
event of the Forgot Password button.
checkResetPasswordOTP
Application developers may use the checkResetPasswordOTP
method to validate if
a given Password Reset OTP is valid. checkResetPasswordOTP
returns a
CheckPasswordResetOtpResponse
where the isOtpValid
property can be extracted from.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { checkResetPasswordOTP } = useUserService();
const { isOtpValid } = await checkResetPasswordOTP('app.ottstream.com', { resetOtp });
completeResetPassword
The second and final step of password reset flow is to call the completeResetPassword
method, along with the Password Reset OTP.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { completeResetPassword } = useUserService();
const completePasswordReset = async(event: React.FormEvent<HTMLFormElement>): Promise<void> => {
event.preventDefault();
const completePasswordResetResponse = await completeResetPassword({newPassword: password, resetOtp: otp});
if (completePasswordResetResponse.code === PasswordResponseCode.SUCCESS) {
window.location.assign('/login');
} else {
setError(completePasswordResetResponse.message ?? 'Error resetting password.');
}
}
The completePasswordReset
method in the example could be called from the onClick
event of the Confirm Password button.
setActiveProfile
In a application where a user can have multiple user profiles, the setActiveProfile
method can be used to set the active profile for a given session. This profile
will be attached to access token and will be sent along with any subsequent requests
to end-user services.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { setActiveProfile } = useUserService();
const handleSelectProfileClick = async (profileId: string) => {
await setActiveProfile(profileId);
history.replace('/');
};
The handleSelectProfileClick
method in the example could be called from the onClick
event of a Select Profile button.
getUserProfile
Application developers can use getUserProfile
to retrieve profile related information
by providing a profileId
. getUserProfile
returns a UserProfile
object.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { getUserProfile } = useUserService();
const userProfile = await getUserProfile(profileId);
getUserProfiles
getUserProfiles
method can be used to retrieved all user profiles for a specific
signed in user. getUserProfiles
returns an array of UserProfile
objects.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { getUserProfiles } = useUserService();
const userProfiles = await getUserProfiles();
createUserProfile
This method can be used to create a new user profile for a user.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { createUserProfile } = useUserService();
const handleAddProfileClick = async () => {
await createUserProfile(displayName);
};
updateUserProfile
This method can be used to update any profile related information for a user.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { updateUserProfile } = useUserService();
const [userProfiles, setUserProfiles] = useState<UserProfile[] | undefined>(
undefined,
);
const handleEditProfileClick = async (userProfileToUpdate: UserProfile) => {
const profileIndex = userProfiles?.findIndex(
(profile) => profile.id === userProfileToUpdate.id,
);
if (profileIndex !== undefined) {
const updatedUserProfiles = [...(userProfiles ?? [])];
updatedUserProfiles[profileIndex] = {
...updatedUserProfiles[profileIndex],
...userProfileToUpdate,
profilePictureUrl: `https://avatars.dicebear.com/api/bottts/${tokenResponse?.userToken?.userId}-${userProfileToUpdate.displayName}.svg`,
};
setUserProfiles(updatedUserProfiles);
}
await updateUserProfile(userProfileToUpdate);
};
deleteUserProfile
This method can be used to delete a user profile.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { updateUserProfile } = useUserService();
const [userProfiles, setUserProfiles] = useState<UserProfile[] | undefined>(
undefined,
);
const handleDeleteProfileClick = async (profileIdToDelete: string) => {
setUserProfiles(
userProfiles?.filter((profile) => profile.id !== profileIdToDelete),
);
await deleteUserProfile(profileIdToDelete);
};
authenticateEndUserApplication
There can be instances where the application developers need to display certain information retrieved from an end-user service, without having a signed in user.
For example, the application needs to list down all the available subscription plans a user can select from when a user registers for the service. At this point, there is no user signed in, but a valid authorization token is required to make the GraphQL call to the Subscription service. Application Tokens can be used for this purpose.
The idea is that just like a user is authenticated, an Application registered in the User Service can be authenticated and in return an access token tailor made for an end-user application can be received. This token can then be used to call any end-user facing GraphQL services, that does not require a signed in user.
authenticateEndUserApplication
returns an
AuthenticateEndUserApplicationResponse.
A EndUserApplicationToken object can be extracted
through the endUserApplicationToken property.
Usage
import { useUserService } from '@axinom/mosaic-user-auth';
const { authenticateEndUserApplication } = useUserService();
const {endUserApplicationToken} = await authenticateEndUserApplication({tenantId, environmentId, applicationId, applicationKey});