New Ory Agent Security is now live! Claim your complimentary test drive. Get Started!

Skip to main content

Last used sign-in method

Returning users often forget which provider they signed in with. Ory Elements can show a Last used badge on the social sign-in or SSO button that a user chose the last time they signed in on the same device. This helps users pick the account they already have instead of creating a second one.

The badge is off by default. With the default storage, the user's choice stays in their browser.

Turn on the badge​

Set show_last_used_method to true in the project configuration that you pass to Ory Elements:

projectConfig.ts
import { ProjectConfiguration } from "@ory/elements-react"

const projectConfig: ProjectConfiguration = {
// ...
show_last_used_method: true,
}

The configuration guide shows how to pass the project configuration to the flow components.

Ory Account Experience has its own switch in Ory Console. See Last used sign-in method in the Ory Account Experience docs.

Where the badge shows​

The badge shows only:

  • On login screens. Registration, recovery, verification, and settings screens don't show it.
  • On social sign-in and SSO buttons (OpenID Connect and SAML). Password, one-time code, and passkey options don't get a badge.
  • On first-factor screens. Second-factor screens never show it.

Which button the badge marks depends on whether the login screen shows the user's identifier, such as their email address:

  • No identifier yet: on the first screen of a login, the badge marks the provider last used on this device. This applies to the identifier step of an identifier-first login and to a one-step login form.
  • Identifier shown: once the screen shows an identifier, the badge marks only the provider last used with that identifier. If that identifier has no record on this device, no badge shows. This applies to the method selection screen of an identifier-first login, to a form shown again after a failed attempt, and to a form with a prefilled identifier.

Because of the second rule, a person on a shared device never sees another person's choice for their own identifier.

What Ory Elements records​

Ory Elements records the method a user chooses in login and registration flows. It records only the first factor. A second factor, such as an authenticator app code or recovery codes, never replaces the record.

MethodWhen Ory Elements records it
Social sign-in and SSOWhen the browser leaves for the identity provider. Ory Elements doesn't learn whether that sign-in succeeds.
Password and one-time codeAfter the sign-in or sign-up succeeds.
Passkey and security keyWhen the user selects the button that opens the browser prompt, even if they then cancel the prompt.

Password, one-time code, and passkey records don't show a badge. Recording them keeps the badge from pointing at a provider the user stopped using.

A passkey that the user picks from the browser's autofill suggestions isn't recorded. On the method selection screen, Ory Elements records a passkey when the user picks it from the list. If you replace Card.AuthMethodListItem with your own component, Ory Elements records the passkey only when your component calls its onClick prop.

During login, Ory Elements also stores the method for the user's identifier when it knows the identifier. That's the case for a password or one-time code sign-in, and for any choice on a screen that shows the identifier. A social sign-in, SSO, or passkey choice on a screen without an identifier, and any registration, update only the method last used on the device.

Before Ory Elements leaves the page for the identity provider or completes a sign-in or sign-up, it waits at most 250 milliseconds for the record to be saved.

Where the record is stored​

By default, Ory Elements stores the record in the browser's localStorage under one key, ory_elements_last_used_method. The value contains:

  • A random salt created for this device.
  • The method last used on this device. For social sign-in and SSO, it also contains the provider ID, for example google.
  • Up to five methods for specific identifiers, most recent first. Each one is stored with a fingerprint of the identifier instead of the identifier. The fingerprint is the first 32 hexadecimal characters of the SHA-256 hash of the salt and the trimmed, lowercased identifier.

The identifier itself is never stored. Because of the salt, a fingerprint can't be computed in advance or matched across devices or sites.

You can classify the value in your consent management tooling as pseudonymous, functional storage, in the same category as a "remember me on this device" option.

When show_last_used_method is off, Ory Elements doesn't read or write the record. It also removes the ory_elements_last_used_method key the next time the browser loads a page with an Ory Elements flow. This applies only to the default storage.

Use your own storage​

To keep the record somewhere else, pass an object that implements LastUsedMethodStorage as the lastUsedMethodStorage prop. Pass the same object to both Login and Registration, or to every OryProvider that renders a login or registration flow. Both flows record the user's choice, and a flow without the prop uses localStorage. If you pass it only to Login, sign-ups still write ory_elements_last_used_method to localStorage, and the login screen never sees those records.

The object has two async methods:

  • get(key) returns the value stored for key, or null if there is none.
  • set(key, value) stores the value and replaces any previous value.

This example keeps the record in sessionStorage, so it lasts until the user closes the browser tab:

lastUsedMethodStorage.ts
import type { LastUsedMethodStorage } from "@ory/elements-react"

export const lastUsedMethodStorage: LastUsedMethodStorage = {
get: async (key) => window.sessionStorage.getItem(key),
set: async (key, value) => {
window.sessionStorage.setItem(key, value)
},
}
AuthForms.tsx
"use client"

import type { LoginFlow, RegistrationFlow } from "@ory/client-fetch"
import { Login, Registration } from "@ory/elements-react/theme"
import { config } from "./config"
import { lastUsedMethodStorage } from "./lastUsedMethodStorage"

export function LoginForm({ flow }: { flow: LoginFlow }) {
return <Login flow={flow} config={config} lastUsedMethodStorage={lastUsedMethodStorage} />
}

export function RegistrationForm({ flow }: { flow: RegistrationFlow }) {
return <Registration flow={flow} config={config} lastUsedMethodStorage={lastUsedMethodStorage} />
}

Keep these points in mind:

  • Define the object outside any component, so that it's the same object on every render.
  • Pass it from a client component. A server component can't pass functions to a client component, so you can't create the storage in a server component and pass it down.
  • Store the value exactly as Ory Elements passes it. Ory Elements checks the value when it reads it and ignores a value that isn't valid.
  • When show_last_used_method is off, Ory Elements doesn't call your storage and doesn't remove its data. Remove the data yourself if you need to.

Build your own badge​

The default theme shows the badge as a small pill on the top edge of the button. It appears once Ory Elements has read the record, without moving the buttons. Its text uses the message ID login.last-used-badge. You can change the text with custom translations.

If you replace the social sign-in button with your own Node.SsoButton component, it receives the isLastUsed prop. The prop is true on the button of the provider the badge would mark:

SsoButton.tsx
import type { OryNodeSsoButtonProps } from "@ory/elements-react"

export function SsoButton({ buttonProps, provider, isLastUsed }: OryNodeSsoButtonProps) {
return (
<button {...buttonProps}>
{provider}
{isLastUsed && <span className="last-used-badge">Last used</span>}
</button>
)
}

Pass it to the flow component as components={{ Node: { SsoButton } }}.

To read the record in any other component, use the useLastUsedMethod hook in a component that renders inside a flow component. It returns the record for the current login screen, following the same rules as the badge. The record has a method, such as oidc, saml, or password, and, for social sign-in and SSO, a provider. Unlike the default badge, the hook also returns password, one-time code, and passkey records.

LastUsedHint.tsx
import { useLastUsedMethod } from "@ory/elements-react"

export function LastUsedHint() {
const lastUsed = useLastUsedMethod()
if (lastUsed?.method !== "oidc") {
return null
}
return <p>Last time, you signed in with {lastUsed.provider}.</p>
}

The hook returns undefined while the record loads, when there is no record, when show_last_used_method is off, outside login flows, and on second-factor screens.

When no badge shows​

Ory Elements never lets the badge break a login. If it can't read the record, it shows no badge. If it can't save the record, it records nothing. In both cases, the login form works as usual. This happens, for example, when:

  • The browser blocks site data, which some private browsing modes do.
  • The stored value is damaged or isn't valid.
  • Your custom storage throws an error or rejects.

Ory Elements computes fingerprints with the Web Crypto API, which browsers provide only on secure pages such as HTTPS pages. Without it, no badge shows on screens that show an identifier.

Reference​