Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

[expo] useLocalCredentials throws "Invalid key provided to SecureStore" during render when the publishable key has base64 padding (=)

Abierto Apto para principiantes
#10,033 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
88/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
react-native, typescript

Línea de trabajo

Comienza en packages/expo/src/local-credentials/useLocalCredentials/useLocalCredentials.ts e inspecciona cómo se utiliza la publishable key para componer las claves de SecureStore e inicializar el hook. Reproduce el problema con la clave con padding del issue en Android o iOS y verifica después que el renderizado ya no lance errores, mientras que las claves existentes sin padding sigan siendo utilizables.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Preliminary Checks
  • I have reviewed the documentation: https://clerk.com/docs
  • I have searched for existing issues: https://github.com/clerk/javascript/issues
  • I have not already reached out to Clerk support via email or Discord
  • This issue is not a question, general help request, or anything other than a bug report directly related to Clerk
Reproduction

No repo link; the bug is two lines in useLocalCredentials and the snippet below reproduces it on any Android or iOS build.

// ClerkProvider publishableKey = "pk_test_dXNlZnVsLWdhdG9yLTU1LmNsZXJrLmFjY291bnRzLmRldiQ="
// (base64 of "useful-gator-55.clerk.accounts.dev$" WITH its trailing "=" padding;
//  parsePublishableKey() accepts it and the rest of the SDK works normally)
import { useLocalCredentials } from "@clerk/expo/local-credentials";

export default function SignIn() {
  useLocalCredentials(); // throws during render, see below
  return null;
}

The error is thrown by expo-secure-store, inside render, and reaches the nearest error boundary:

Error: Invalid key provided to SecureStore. Keys must not be empty and contain only
alphanumeric characters, ".", "-", and "_".
    at SignInScreen
    ...
    isComponentError: true
Publishable key

pk_test_dXNlZnVsLWdhdG9yLTU1LmNsZXJrLmFjY291bnRzLmRldiQ=

Description

useLocalCredentials composes its two secure-store keys from the raw publishable key and reads the first one with the synchronous getItem as a useState initialiser (packages/expo/src/local-credentials/useLocalCredentials/useLocalCredentials.ts):

const key = `__clerk_local_auth_${publishableKey}_identifier`;
const pkey = `__clerk_local_auth_${publishableKey}_password`;
const [hasLocalAuthCredentials, setHasLocalAuthCredentials] = useState(!!getItem(key));

expo-secure-store validates every key against /^[\w.-]+$/ and throws otherwise. A publishable key is pk_*_ + base64 of <frontend host>$, and the base64 of that string carries = padding whenever len(host) + 1 is not a multiple of 3. parsePublishableKey decodes a padded key fine (atob tolerates either form), so the provider, useSignIn, SSO and everything else work with such a key; only this hook crashes, and it crashes the whole screen that renders it rather than the biometric feature alone.

In our case the padded key was produced by base64-encoding the frontend host ourselves for a release build against a dev instance (the keys the dashboard hands out appear to be emitted without padding, which is presumably why this is rarely hit). But since the SDK accepts padded keys everywhere else, this hook should too, and the failure mode (a render-time throw from a useState initialiser) is disproportionate.

Related: #9870 fixed the same class of problem for the offline resource cache by keying on the full publishable key "with trailing = characters removed". The same treatment here fixes it:

const storeKeyBase = publishableKey.replace(/[^\w.-]/g, "");
const key = `__clerk_local_auth_${storeKeyBase}_identifier`;
const pkey = `__clerk_local_auth_${storeKeyBase}_password`;

Keys without padding are unchanged by the replace, so existing stored credentials keep their key. We are shipping exactly this as a pnpm patch on @clerk/[email protected]; I checked 4.8.0 and it still composes the raw key.

Environment
@clerk/expo 4.2.7 (also inspected 4.8.0 dist)
@clerk/shared 4.28.1
expo 57.0.24
expo-secure-store 57.0.4
expo-local-authentication 57.0.3
react-native 0.86.3
react 19.2.3
node 24.10.0
Device: Pixel, Android 17, release (non dev-client) EAS build
Lenguaje dominante
TypeScript
Estrellas
1.8k
Forks
473
Merge medio
2 d 2 h
PR fusionados (30 d)
253

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de clerk/javascript

Todos los issues de clerk/javascript

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.