@saleor/sdk
Version:
Saleor TS SDK
516 lines (477 loc) • 14.6 kB
text/typescript
import {
CHANGE_USER_PASSWORD,
EXTERNAL_AUTHENTICATION_URL,
EXTERNAL_LOGOUT,
EXTERNAL_REFRESH,
EXTERNAL_REFRESH_WITH_USER,
EXTERNAL_VERIFY_TOKEN,
LOGIN,
LOGIN_WITHOUT_DETAILS,
OBTAIN_EXTERNAL_ACCESS_TOKEN,
REFRESH_TOKEN,
REFRESH_TOKEN_WITH_USER,
REGISTER,
REQUEST_PASSWORD_RESET,
SET_PASSWORD,
VERIFY_TOKEN,
} from "../apollo/mutations";
import { USER, USER_WITHOUT_DETAILS } from "../apollo/queries";
import {
ExternalAuthenticationUrlMutation,
ExternalAuthenticationUrlMutationVariables,
ExternalLogoutMutation,
ExternalLogoutMutationVariables,
ExternalObtainAccessTokensMutation,
ExternalObtainAccessTokensMutationVariables,
ExternalRefreshMutation,
ExternalRefreshMutationVariables,
ExternalRefreshWithUserMutation,
ExternalRefreshWithUserMutationVariables,
ExternalVerifyMutation,
ExternalVerifyMutationVariables,
LoginMutation,
LoginMutationVariables,
PasswordChangeMutation,
PasswordChangeMutationVariables,
RefreshTokenMutation,
RefreshTokenMutationVariables,
RefreshTokenWithUserMutation,
RefreshTokenWithUserMutationVariables,
RegisterMutation,
RegisterMutationVariables,
RequestPasswordResetMutation,
RequestPasswordResetMutationVariables,
SetPasswordMutation,
SetPasswordMutationVariables,
VerifyTokenMutation,
VerifyTokenMutationVariables,
} from "../apollo/types";
import { hasNonEmptyPermissions } from "./helpers";
import { storage } from "./storage";
import {
ChangePasswordOpts,
ChangePasswordResult,
GetExternalAccessTokenOpts,
GetExternalAccessTokenResult,
GetExternalAuthUrlOpts,
GetExternalAuthUrlResult,
LoginOpts,
LoginResult,
LogoutOpts,
LogoutResult,
RefreshExternalTokenResult,
RefreshTokenResult,
RegisterOpts,
RegisterResult,
RequestPasswordResetOpts,
RequestPasswordResetResult,
SaleorClientMethodsProps,
SetPasswordOpts,
SetPasswordResult,
VerifyExternalTokenResult,
VerifyTokenResult,
} from "./types";
export interface AuthSDK {
/**
* Change the password of the logged in user.
*
* @param opts - Object with password and new password.
* @returns Errors if the passoword change has failed.
*/
changePassword: (opts: ChangePasswordOpts) => Promise<ChangePasswordResult>;
/**
* Authenticates user with email and password.
*
* @param opts - Object with user's email, password and a boolean includeDetails - whether to fetch user details.
* Default for includeDetails is true.
* @returns Promise resolved with CreateToken type data.
*/
login: (opts: LoginOpts) => Promise<LoginResult>;
/**
* Clears stored token and Apollo store. If external plugin was used to log in, the mutation will prepare
* the logout URL. All values passed in field input will be added as GET parameters to the logout request.
*
* @param opts - Object with input as JSON with returnTo - the URL where a user should be redirected
* when external plugin was used to log in
* @returns Logout data and errors if external plugin was used to log in. Otherwise null.
*/
logout: (opts?: LogoutOpts) => Promise<LogoutResult>;
/**
* Refresh JWT token. Mutation will try to take refreshToken from the function's arguments.
* If it fails, it will try to use refreshToken from the http-only cookie called refreshToken.
*
* @param includeUser - Whether to fetch user. Default false.
* @returns Authorization token.
*/
refreshToken: (includeUser?: boolean) => Promise<RefreshTokenResult>;
/**
* Registers user with email and password.
*
* @param opts - Object with user's data. Email and password are required fields.
* "channel" can be changed by using first "setChannel" method from api.
* @returns Promise resolved with AccountRegister type data.
*/
register: (opts: RegisterOpts) => Promise<RegisterResult>;
/**
* Sends an email with the account password modification link.
*
* @param opts - Object with slug of a channel which will be used for notify user,
* email of the user that will be used for password recovery and URL of a view
* where users should be redirected to reset the password. URL in RFC 1808 format.
*
* @returns Errors if there were some.
*/
requestPasswordReset: (
opts: RequestPasswordResetOpts
) => Promise<RequestPasswordResetResult>;
/**
* Sets the user's password from the token sent by email.
*
* @param opts - Object with user's email, password and one-time token required to set the password.
* @returns User instance, JWT token, JWT refresh token and CSRF token.
*/
setPassword: (opts: SetPasswordOpts) => Promise<SetPasswordResult>;
/**
* Verify JWT token.
*
* @param token - Token value.
* @returns User assigned to token and the information if the token is valid or not.
*/
verifyToken: () => Promise<VerifyTokenResult>;
/**
* Executing externalAuthenticationUrl mutation will prepare special URL which will redirect user to requested
* page after successfull authentication. After redirection state and code fields will be added to the URL.
*
* @param opts - Object withpluginId default value set as "mirumee.authentication.openidconnect" and input as
* JSON with redirectUrl - the URL where the user should be redirected after successful authentication.
* @returns Authentication data and errors
*/
getExternalAuthUrl: (
opts: GetExternalAuthUrlOpts
) => Promise<GetExternalAuthUrlResult>;
/**
* The externalObtainAccessTokens mutation will generate requested access tokens.
*
* @param opts - Object withpluginId default value set as "mirumee.authentication.openidconnect" and input as
* JSON with code - the authorization code received from the OAuth provider and state - the state value received
* from the OAuth provider
* @returns Login authentication data and errors
*/
getExternalAccessToken: (
opts: GetExternalAccessTokenOpts
) => Promise<GetExternalAccessTokenResult>;
/**
* The externalRefresh mutation will generate new access tokens when provided with a valid refresh token.
*
* @param includeUser - Whether to fetch user. Default false.
* @returns Token refresh data and errors
*/
refreshExternalToken: (
includeUser?: boolean
) => Promise<RefreshExternalTokenResult>;
/**
* The mutation will verify the authentication token.
*
* @returns Token verification data and errors
*/
verifyExternalToken: () => Promise<VerifyExternalTokenResult>;
}
export const auth = ({
apolloClient: client,
channel,
}: SaleorClientMethodsProps): AuthSDK => {
const login: AuthSDK["login"] = ({ includeDetails = true, ...opts }) => {
const query = includeDetails ? USER : USER_WITHOUT_DETAILS;
const loginMutation = includeDetails ? LOGIN : LOGIN_WITHOUT_DETAILS;
client.writeQuery({
query,
data: {
authenticating: true,
},
});
return client.mutate<LoginMutation, LoginMutationVariables>({
mutation: loginMutation,
variables: {
...opts,
},
update: (_, { data }) => {
if (data?.tokenCreate?.token) {
storage.setTokens({
accessToken: data.tokenCreate.token,
refreshToken: data.tokenCreate.refreshToken,
});
} else {
client.writeQuery({
query,
data: {
authenticating: false,
},
});
}
},
});
};
const logout: AuthSDK["logout"] = async opts => {
const authPluginId = storage.getAuthPluginId();
storage.clear();
client.writeQuery({
query: USER,
data: {
authenticating: false,
},
});
client.resetStore();
if (authPluginId && opts?.input) {
const result = await client.mutate<
ExternalLogoutMutation,
ExternalLogoutMutationVariables
>({
mutation: EXTERNAL_LOGOUT,
variables: {
...opts,
pluginId: authPluginId,
},
});
return result;
}
return null;
};
const register: AuthSDK["register"] = async opts =>
await client.mutate<RegisterMutation, RegisterMutationVariables>({
mutation: REGISTER,
variables: {
input: {
...opts,
channel,
},
},
});
const refreshToken: AuthSDK["refreshToken"] = (includeUser = false) => {
const refreshToken = storage.getRefreshToken();
if (!refreshToken) {
throw Error("refreshToken not present");
}
if (includeUser) {
return client.mutate<
RefreshTokenWithUserMutation,
RefreshTokenWithUserMutationVariables
>({
mutation: REFRESH_TOKEN_WITH_USER,
variables: {
refreshToken,
},
update: (_, { data }) => {
if (data?.tokenRefresh?.token) {
storage.setAccessToken(data.tokenRefresh.token);
} else {
logout();
}
},
});
}
return client.mutate<RefreshTokenMutation, RefreshTokenMutationVariables>({
mutation: REFRESH_TOKEN,
variables: {
refreshToken,
},
update: (_, { data }) => {
if (data?.tokenRefresh?.token) {
storage.setAccessToken(data.tokenRefresh.token);
} else {
logout();
}
},
});
};
const verifyToken: AuthSDK["verifyToken"] = async () => {
const token = storage.getAccessToken();
if (!token) {
throw Error("Token not present");
}
const result = await client.mutate<
VerifyTokenMutation,
VerifyTokenMutationVariables
>({
mutation: VERIFY_TOKEN,
variables: { token },
});
if (!result.data?.tokenVerify?.isValid) {
logout();
}
return result;
};
const changePassword: AuthSDK["changePassword"] = async opts => {
const result = await client.mutate<
PasswordChangeMutation,
PasswordChangeMutationVariables
>({
mutation: CHANGE_USER_PASSWORD,
variables: { ...opts },
});
return result;
};
const requestPasswordReset: AuthSDK["requestPasswordReset"] = async opts => {
const result = await client.mutate<
RequestPasswordResetMutation,
RequestPasswordResetMutationVariables
>({
mutation: REQUEST_PASSWORD_RESET,
variables: { ...opts, channel },
});
return result;
};
const setPassword: AuthSDK["setPassword"] = opts => {
return client.mutate<SetPasswordMutation, SetPasswordMutationVariables>({
mutation: SET_PASSWORD,
variables: { ...opts },
update: (_, { data }) => {
if (data?.setPassword?.token) {
storage.setTokens({
accessToken: data.setPassword.token,
refreshToken: data.setPassword.refreshToken,
});
}
},
});
};
const getExternalAuthUrl: AuthSDK["getExternalAuthUrl"] = async opts => {
const result = await client.mutate<
ExternalAuthenticationUrlMutation,
ExternalAuthenticationUrlMutationVariables
>({
mutation: EXTERNAL_AUTHENTICATION_URL,
variables: { ...opts },
});
return result;
};
const getExternalAccessToken: AuthSDK["getExternalAccessToken"] = opts => {
client.writeQuery({
query: USER,
data: {
authenticating: true,
},
});
return client.mutate<
ExternalObtainAccessTokensMutation,
ExternalObtainAccessTokensMutationVariables
>({
mutation: OBTAIN_EXTERNAL_ACCESS_TOKEN,
variables: {
...opts,
},
update: (_, { data }) => {
storage.setAuthPluginId(opts.pluginId);
if (
data?.externalObtainAccessTokens?.token &&
hasNonEmptyPermissions(
data?.externalObtainAccessTokens?.user?.userPermissions
)
) {
storage.setTokens({
accessToken: data.externalObtainAccessTokens.token,
refreshToken: data.externalObtainAccessTokens.refreshToken,
});
} else {
client.writeQuery({
query: USER,
data: {
authenticating: false,
},
});
}
},
});
};
const refreshExternalToken: AuthSDK["refreshExternalToken"] = (
includeUser = false
) => {
const refreshToken = storage.getRefreshToken();
const authPluginId = storage.getAuthPluginId();
if (!refreshToken) {
throw Error("refreshToken not present");
}
if (includeUser) {
return client.mutate<
ExternalRefreshWithUserMutation,
ExternalRefreshWithUserMutationVariables
>({
mutation: EXTERNAL_REFRESH_WITH_USER,
variables: {
pluginId: authPluginId,
input: JSON.stringify({
refreshToken,
}),
},
update: (_, { data }) => {
if (data?.externalRefresh?.token) {
storage.setTokens({
accessToken: data.externalRefresh.token,
refreshToken: data.externalRefresh.refreshToken,
});
} else {
logout();
}
},
});
}
return client.mutate<
ExternalRefreshMutation,
ExternalRefreshMutationVariables
>({
mutation: EXTERNAL_REFRESH,
variables: {
pluginId: authPluginId,
input: JSON.stringify({
refreshToken,
}),
},
update: (_, { data }) => {
if (data?.externalRefresh?.token) {
storage.setTokens({
accessToken: data.externalRefresh.token,
refreshToken: data.externalRefresh.refreshToken,
});
} else {
logout();
}
},
});
};
const verifyExternalToken: AuthSDK["verifyExternalToken"] = async () => {
const refreshToken = storage.getRefreshToken();
const authPluginId = storage.getAuthPluginId();
if (!refreshToken) {
throw Error("refreshToken not present");
}
const result = await client.mutate<
ExternalVerifyMutation,
ExternalVerifyMutationVariables
>({
mutation: EXTERNAL_VERIFY_TOKEN,
variables: {
pluginId: authPluginId,
input: JSON.stringify({
refreshToken,
}),
},
});
if (!result.data?.externalVerify?.isValid) {
storage.clear();
}
return result;
};
return {
changePassword,
getExternalAccessToken,
getExternalAuthUrl,
login,
logout,
refreshExternalToken,
refreshToken,
register,
requestPasswordReset,
setPassword,
verifyExternalToken,
verifyToken,
};
};