# Login links

> Single-use sign-in URLs for magic links in your own emails, or to move a signed-in user from your app to 9in.

Source: https://9in.io/docs/login-links/

A login link is a single-use URL that signs one user in. Use it for:

- **Magic links in your own emails** ("Click to sign in"), sent by your mail system with your templates.
- **Moving a signed-in user from your app to 9in** without asking for their password again, for example when you add 9in to an existing product and want users to land on the account page already signed in.

Your back end creates links with the [Management API](https://9in.io/docs/reference/management-api/); browsers never can.

## Create a link

The application needs the `management:users:write` scope (**Applications → your machine-to-machine app → API Access**).

```ts
import { ManagementClient } from "@9in-io/sdk/server";

const nine = new ManagementClient({ issuer: "https://acme.9in.io", clientId, clientSecret });
const { url, expires_at } = await nine.createLoginLink(userId, {
  returnTo: "https://app.acme.com/callback",   // where the user ends up
  ttlSeconds: 600,                              // 60 to 3600; default 600
});
// email `url`, or redirect the user to it
```

```bash
curl -X POST https://acme.9in.io/api/v1/users/usr_8k2…/login-link \
  -H "Authorization: Bearer $MGMT_TOKEN" -H "Content-Type: application/json" \
  -d '{ "return_to": "https://app.acme.com/callback", "ttl_seconds": 600 }'
# → 201 { "url": "https://acme.9in.io/login/link?token=…", "expires_at": 1794200600 }
```

## Where users land

`return_to` must be one of:

- a **registered callback URL** of one of your applications. The user is signed in to 9in and sent there; your app then starts a normal sign-in (`auth.login()`), which completes at once because the user has a session (single sign-on);
- a **path on the login domain**, such as `/account`.

Without `return_to`, the user lands on their account page.

## Rules

- **Single use** and short-lived: a link works once, within its lifetime (1 minute to 1 hour, 10 minutes by default).
- **Two-factor still applies:** a user with two-factor turned on is asked for their code after opening the link.
- **Blocked users** can't get links (409).
- Signing in with a link counts as a sign-in (`user.login` webhook) with `link` in the ID token's `amr`.
- Every link is recorded: the console's activity log shows who created it (`user.login_link_created`).

Admins can also create a 15-minute link for a user from the console (**Users → user → Sign-in link**) to help them sign in.
