# prepareSsoUrl

> **prepareSsoUrl**(`client`, `args`): `Promise`\<[`PrepareSsoReturnType`](/developers/references/core-sdk/index/type-aliases/preparessoreturntype/)\>

Defined in: actions/prepareSsoUrl.ts:64

Build the SSO popup URL without opening it.

Everything [openSso](/developers/references/core-sdk/actions/functions/opensso/) does before `window.open`, and nothing else:
resolves the client and merchant ids, mints the `frak-sso-v1`
proof-of-possession, and compresses the whole lot into the URL.

Call this ahead of the user's gesture — on mount, on hover, on focus — and
hand the result to `openSso(client, { ssoUrl })`, which then opens the popup
in the same tick as the click. That is the only way to reliably dodge popup
blockers, since `openSso`'s all-in-one form has to await id resolution and
proof signing first.

## Parameters

### client

[`FrakClient`](/developers/references/core-sdk/index/type-aliases/frakclient/)

The current Frak Client

### args

[`PrepareSsoParamsType`](/developers/references/core-sdk/index/type-aliases/preparessoparamstype/)

The SSO parameters

## Returns

`Promise`\<[`PrepareSsoReturnType`](/developers/references/core-sdk/index/type-aliases/preparessoreturntype/)\>

Object containing the generated `ssoUrl`

## Example

```tsx
// Prepared ahead of time, so the click handler stays synchronous
const { data } = useQuery({
    queryKey: ["sso-url"],
    queryFn: () => prepareSsoUrl(client, { metadata }),
});

<button onClick={() => data && openSso(client, { ssoUrl: data.ssoUrl })}>
    Login
</button>
```

## Remarks

The proof is minted at prepare time and carries a 10-minute validity window.
A URL prepared and left unused for longer still opens SSO and still logs the
user in — only the anonymous-to-wallet identity link is dropped. Re-prepare
on a long-lived page rather than holding one URL indefinitely.

Not to be confused with [prepareSso](/developers/references/core-sdk/actions/functions/preparesso/), which asks the wallet iframe to
build the URL over RPC and cannot mint a proof.