Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
302edb1
parents translate, components receive plain strings
a-elkhiraooui-ciscode Jan 28, 2026
0258a6e
1.0.3
a-elkhiraooui-ciscode Jan 28, 2026
a62f9b7
tested in local, bug fixed
a-elkhiraooui-ciscode Jan 29, 2026
3bd91d4
1.0.4
a-elkhiraooui-ciscode Jan 29, 2026
68a2b0a
Merge branch 'master' of https://github.com/CISCODE-MA/AuthKit-UI int…
a-elkhiraooui-ciscode Jan 29, 2026
91f6973
Merge branch 'master' of https://github.com/CISCODE-MA/AuthKit-UI int…
a-elkhiraooui-ciscode Jan 30, 2026
b13ea31
forgot and reset password done
a-elkhiraooui-ciscode Jan 30, 2026
c20676e
1.0.6
a-elkhiraooui-ciscode Jan 30, 2026
3fe9bc8
verify email page done
a-elkhiraooui-ciscode Feb 2, 2026
976a57f
Merge branch 'master' of https://github.com/CISCODE-MA/AuthKit-UI int…
a-elkhiraooui-ciscode Feb 2, 2026
c872138
merged
a-elkhiraooui-ciscode Feb 2, 2026
d675672
1.0.10
a-elkhiraooui-ciscode Feb 2, 2026
ea372ac
Merge branch 'develop' of https://github.com/CISCODE-MA/AuthKit-UI in…
a-elkhiraooui-ciscode Feb 2, 2026
1f17429
updated endpoints
a-elkhiraooui-ciscode Feb 2, 2026
8844b2d
endpoints fixed
a-elkhiraooui-ciscode Feb 3, 2026
1c2ac98
show profile updated to match new response
a-elkhiraooui-ciscode Feb 3, 2026
d0653e2
added unit tests
a-elkhiraooui-ciscode Feb 3, 2026
463c1a5
added error handling to forgot password, reset password and signin/up…
a-elkhiraooui-ciscode Feb 4, 2026
f062b2a
Merge branch 'master' of https://github.com/CISCODE-MA/AuthKit-UI int…
a-elkhiraooui-ciscode Feb 4, 2026
f341eb4
1.0.13
a-elkhiraooui-ciscode Feb 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ciscode/ui-authentication-kit",
"version": "1.0.12",
"version": "1.0.13",
"description": "",
"main": "dist/index.umd.js",
"module": "dist/index.mjs",
Expand Down
8 changes: 5 additions & 3 deletions src/pages/auth/ForgotPasswordPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { InlineError } from "../../components/InlineError";
import { useAuthConfig } from "../../context/AuthConfigContext";
import { useAuthState } from "../../context/AuthStateContext";
import { toTailwindColorClasses } from "../../utils/colorHelpers";
import { extractHttpErrorMessage } from "../../utils/errorHelpers";

export const ForgotPasswordPage: React.FC = () => {
const t = useT("authLib");
Expand All @@ -31,9 +32,10 @@ export const ForgotPasswordPage: React.FC = () => {
// Always show generic success regardless of user existence
setSent(true);
} catch (err) {
// Do not enumerate users; still show success message
setSent(true);
console.error("Forgot password request failed", err);
// Show backend error details.message via InlineError
const msg = extractHttpErrorMessage(err);
setError(msg);
setSent(false);
} finally {
setPending(false);
}
Expand Down
13 changes: 3 additions & 10 deletions src/pages/auth/ResetPasswordPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { InlineError } from "../../components/InlineError";
import { useAuthConfig } from "../../context/AuthConfigContext";
import { useAuthState } from "../../context/AuthStateContext";
import { toTailwindColorClasses } from "../../utils/colorHelpers";
import { extractHttpErrorMessage } from "../../utils/errorHelpers";

export const ResetPasswordPage: React.FC = () => {
const t = useT("authLib");
Expand Down Expand Up @@ -53,16 +54,8 @@ export const ResetPasswordPage: React.FC = () => {
// On success, show brief confirmation then navigate to login
navigate("/login", { replace: true });
} catch (err: any) {
const status = err?.response?.status;
if (status === 400 || status === 401 || status === 410) {
setError(
t("ResetPasswordPage.invalidOrExpired", {
defaultValue: "Reset link is invalid or has expired. Request a new one.",
})
);
} else {
setError(t("errors.generic", { defaultValue: "Something went wrong. Please try again." }));
}
const msg = extractHttpErrorMessage(err);
setError(msg);
} finally {
setPending(false);
}
Expand Down
18 changes: 12 additions & 6 deletions src/pages/auth/SignInPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { InputField } from "../../components/actions/InputField";
import { SocialButton } from "../../components/actions/SocialButton";
import googleIcon from "../../assets/icons/google-icon-svgrepo-com.svg";
Expand All @@ -7,6 +7,7 @@ import { toTailwindColorClasses } from "../../utils/colorHelpers";
import { useAuthConfig } from "../../context/AuthConfigContext";
import { useAuthState } from "../../context/AuthStateContext";
import { InlineError } from "../../components/InlineError";
import { extractHttpErrorMessage } from "../../utils/errorHelpers";
import { AuthConfigProps } from "../../models/AuthConfig";
import { useT } from "@ciscode/ui-translate-core";
import { useNavigate, useLocation } from "react-router-dom";
Expand Down Expand Up @@ -39,6 +40,14 @@ export const SignInPage: React.FC<AuthConfigProps> = () => {
const [password, setPassword] = useState("");
const [pending, setPending] = useState(false);
const [error, setError] = useState<string | null>(null);
// Show any provider-level error surfaced by the interceptor (e.g., refresh failures)
useEffect(() => {
const msg = sessionStorage.getItem('authErrorMessage');
if (msg) {
setError(msg);
sessionStorage.removeItem('authErrorMessage');
}
}, []);

const allProvidersData = {
google: { icon: googleIcon, label: t("social.google") },
Expand All @@ -64,11 +73,8 @@ export const SignInPage: React.FC<AuthConfigProps> = () => {
try {
await login({ email, password });
} catch (err: any) {
if (err?.response?.status === 401) {
setError(t("errors.invalidCredentials"));
} else {
setError(t("errors.generic"));
}
const msg = extractHttpErrorMessage(err);
setError(msg);
} finally {
setPending(false);
}
Expand Down
24 changes: 3 additions & 21 deletions src/pages/auth/SignUpPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { toTailwindColorClasses } from "../../utils/colorHelpers";
import { useAuthConfig } from "../../context/AuthConfigContext";
import { useAuthState } from "../../context/AuthStateContext";
import { InlineError } from "../../components/InlineError";
import { extractHttpErrorMessage } from "../../utils/errorHelpers";
import { useT } from "@ciscode/ui-translate-core";
import { useNavigate, useLocation } from "react-router-dom";

Expand Down Expand Up @@ -83,27 +84,8 @@ export const SignUpPage: React.FC = () => {
navigate(`/verify-email?email=${encodeURIComponent(email)}`, { replace: true });
return;
} catch (err: any) {
const status = err?.response?.status;
if (status === 400) {
setError(
err?.response?.data?.message ||
t("errors.invalidData", {
defaultValue: "Please check the fields and try again.",
})
);
} else if (status === 409) {
setError(
t("errors.emailInUse", {
defaultValue: "This email is already in use.",
})
);
} else {
setError(
t("errors.generic", {
defaultValue: "Something went wrong. Please try again.",
})
);
}
const msg = extractHttpErrorMessage(err);
setError(msg);
} finally {
setPending(false);
}
Expand Down
9 changes: 9 additions & 0 deletions src/utils/attachAuthInterceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import axios, {
AxiosRequestConfig,
InternalAxiosRequestConfig,
} from 'axios';
import { extractHttpErrorMessage } from './errorHelpers';

interface Options {
baseUrl: string; // e.g. https://api.myapp.com
Expand Down Expand Up @@ -60,6 +61,14 @@ export function attachAuthInterceptor(api: AxiosInstance, opts: Options) {
opts.logout(); // 🔔 open modal, keep token for now
}

// Surface detailed error message for UI to display on login page
try {
const msg = extractHttpErrorMessage(refreshErr);
if (msg) {
sessionStorage.setItem('authErrorMessage', msg);
}
} catch { /* ignore storage errors */ }

queue.forEach(cb => cb(null));
queue = [];
return Promise.reject(refreshErr);
Expand Down
47 changes: 47 additions & 0 deletions src/utils/errorHelpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import type { AxiosError } from 'axios';

type ErrorResponse = {
ok?: boolean;
code?: string;
message?: string;
requestId?: string;
path?: string;
details?: {
message?: string;
error?: string;
statusCode?: number;
};
};

function isAxiosError(err: unknown): err is AxiosError {
return !!(err as any)?.isAxiosError;
}

/**
* Extract a user-facing error message from common backend/HTTP shapes.
* Preference order:
* 1) response.data.details.message
* 2) response.data.message
* 3) response.data.details.error
* 4) err.message
* 5) generic fallback
*/
export function extractHttpErrorMessage(err: unknown): string {
try {
if (typeof err === 'string') return err;

if (isAxiosError(err)) {
const data = err.response?.data as ErrorResponse | undefined;
const fromResponse =
data?.details?.message?.toString()?.trim() ||
data?.message?.toString()?.trim() ||
data?.details?.error?.toString()?.trim();
if (fromResponse) return fromResponse;
if (err.message) return err.message;
}

if (err instanceof Error && err.message) return err.message;
} catch {/* ignore parsing issues */}

return 'An unexpected error occurred';
}