> **Building with AI coding agents?** If you're using an AI coding agent, install the official Scalekit plugin. It gives your agent full awareness of the Scalekit API — reducing hallucinations and enabling faster, more accurate code generation.
>
> - **Claude Code**: `/plugin marketplace add scalekit-inc/claude-code-authstack` then `/plugin install <auth-type>@scalekit-auth-stack`
> - **GitHub Copilot CLI**: `copilot plugin marketplace add scalekit-inc/github-copilot-authstack` then `copilot plugin install <auth-type>@scalekit-auth-stack`
> - **Codex**: run the bash installer, restart, then open Plugin Directory and enable `<auth-type>`
> - **Skills CLI** (Windsurf, Cline, 40+ agents): `npx skills add scalekit-inc/skills --list` then `--skill <skill-name>`
>
> `<auth-type>` / `<skill-name>`: `agent-auth`, `full-stack-auth`, `mcp-auth`, `modular-sso`, `modular-scim` — [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# Passwordless OIDC Quickstart

This guide shows you how to implement passwordless authentication with Scalekit over OIDC protocol. Users verify with a email verification code (OTP) or a magic link or both.

<details>
<summary><IconTdesignSequence style="display: inline; width: 1rem; height: 1rem; vertical-align: middle; margin-right: 0.5rem;" /> Review the authentication sequence</summary>

```d2

shape: sequence_diagram

User -> Scalekit: "Enter email address"
Scalekit -> User: "Send OTP or magic link"
User -> Scalekit: "Verify identity (OTP/magic link)"
Scalekit <> Your app: "Exchange code for user details"
Your app -> User: "Create session and grant access"

```
</details>

<FoldCard
  title="Build with a coding agent"
  iconKey="build-with-ai"
  iconPosition="right"
  href="/dev-kit/build-with-ai/full-stack-auth/"
  cta="Build with AI"
  showCta={false}
  clickable={false}
>
  ```bash title="Claude REPL" showLineNumbers=false frame="none"
    /plugin marketplace add scalekit-inc/claude-code-authstack
    ```
    ```bash title="Claude REPL" showLineNumbers=false frame="none"
    /plugin install full-stack-auth@scalekit-auth-stack
    ```
   ```bash title="Terminal" showLineNumbers=false frame="none"
    copilot plugin marketplace add scalekit-inc/github-copilot-authstack
    ```
    ```bash title="Terminal" showLineNumbers=false frame="none"
    copilot plugin install full-stack-auth@scalekit-auth-stack
    ```
   ```bash title="Terminal" showLineNumbers=false frame="none"
    npx skills add scalekit-inc/skills --skill implementing-scalekit-fsa
    ```
   [Continue building with AI →](/dev-kit/build-with-ai/full-stack-auth/)
</FoldCard>

1. ## Set up Scalekit and register a callback endpoint

   Follow the [installation guide](/authenticate/set-up-scalekit/) to configure Scalekit in your application.

   Scalekit verifies user identities and creates sessions. After successful verification, Scalekit creates a user record and sends the user information to your callback endpoint.

   **Create a callback endpoint:**

1. Add a callback endpoint to your application (typically `https://your-app.com/auth/callback`)
2. Register this URL in your Scalekit dashboard

   Learn more about [callback URL requirements](/guides/dashboard/redirects/#allowed-callback-urls).

2. ## Configure passwordless settings

   In the Scalekit dashboard, enable Magic link & OTP and choose your login method.

   Optional security settings:
   - **Enforce same-browser origin**: Users must complete magic-link auth in the same browser they started in.
   - **Issue new credentials on resend**: Each resend generates a fresh code or link and invalidates the previous one.

    ![](@/assets/docs/fsa/auth-methods/1.png)

3. ## Redirect users to sign up (or) login

   Create an authorization URL and redirect users to Scalekit's sign-in page. Include:

   | Parameter | Description |
   |-----------|-------------|
   | `redirect_uri` | Your app's callback endpoint (for example, `https://your-app.com/auth/callback`). |
   | `client_id` | Your Scalekit application identifier (scoped to the environment). |
   | `login_hint` | The user's email address to receive the verification email. |

   **Example implementation**

    ```javascript showLineNumbers wrap
    import { ScalekitClient } from '@scalekit-sdk/node';
    // Initialize the SDK client
    const scalekit = new ScalekitClient(
      '<SCALEKIT_ENVIRONMENT_URL>',
      '<SCALEKIT_CLIENT_ID>',
      '<SCALEKIT_CLIENT_SECRET>',
    );

    const options = {};

    options['loginHint'] = 'user@example.com';

    const authorizationUrl = scalekit.getAuthorizationUrl(redirectUri, options);
    // Generated URL will look like:
    // https://<SCALEKIT_ENVIRONMENT_URL>/oauth/authorize?response_type=code&client_id=skc_1234&scope=openid%20profile%20email&redirect_uri=https%3A%2F%2Fyourapp.com%2Fcallback

    res.redirect(authorizationUrl);
    ```

    ```python showLineNumbers wrap
    from scalekit import ScalekitClient, AuthorizationUrlOptions, CodeAuthenticationOptions

    # Initialize the SDK client
    scalekit = ScalekitClient(
      '<SCALEKIT_ENVIRONMENT_URL>',
      '<SCALEKIT_CLIENT_ID>',
      '<SCALEKIT_CLIENT_SECRET>'
    )

    options = AuthorizationUrlOptions()

    # Authorization URL with login hint
    options.login_hint = 'user@example.com'

    authorization_url = scalekit.get_authorization_url(redirect_uri, options)
    # Generated URL will look like:
    # https://<SCALEKIT_ENVIRONMENT_URL>/oauth/authorize?response_type=code&client_id=skc_1234&scope=openid%20profile%20email&redirect_uri=https%3A%2F%2Fyourapp.com%2Fcallback

    return redirect(authorization_url)
    ```

    ```go showLineNumbers
    import (
      "github.com/scalekit-inc/scalekit-sdk-go"
    )

    func main() {
      // Initialize the SDK client
      scalekitClient := scalekit.NewScalekitClient(
        "<SCALEKIT_ENVIRONMENT_URL>",
        "<SCALEKIT_CLIENT_ID>",
        "<SCALEKIT_CLIENT_SECRET>"
      )

      options := scalekitClient.AuthorizationUrlOptions{}
      // User's email domain detects the correct enterprise SSO connection.
      options.LoginHint = "user@example.com"

      authorizationURL := scalekitClient.GetAuthorizationUrl(
        redirectUrl,
        options,
      )
      // Next step is to redirect the user to this authorization URL
    }

    // Redirect the user to this authorization URL
    ```

    ```java showLineNumbers
    package com.scalekit;

    import com.scalekit.ScalekitClient;
    import com.scalekit.internal.http.AuthorizationUrlOptions;

    public class Main {

      public static void main(String[] args) {
        // Initialize the SDK client
        ScalekitClient scalekitClient = new ScalekitClient(
          "<SCALEKIT_ENVIRONMENT_URL>",
          "<SCALEKIT_CLIENT_ID>",
          "<SCALEKIT_CLIENT_SECRET>"
        );
        AuthorizationUrlOptions options = new AuthorizationUrlOptions();
        // User's email domain detects the correct enterprise SSO connection.
        options.setLoginHint("user@example.com");
        try {
          String url = scalekitClient
            .authentication()
            .getAuthorizationUrl(redirectUrl, options)
            .toString();
        } catch (Exception e) {
          System.out.println(e.getMessage());
        }
      }
    }
    // Redirect the user to this authorization URL
    ```
    This redirects users to Scalekit's authentication flow. After verification, they return to your application.

    <details>
    <summary>Example authorization URL</summary>

    ```sh title="Example authorization URL"
    <YOURAPP_SCALEKIT_ENVIRONMENT_URL>/oauth/authorize?
      client_id=skc_122056050118122349527&
      redirect_uri=https://yourapp.com/auth/callback&
      login_hint=user@example.com&
      response_type=code&
      scope=openid%20profile%20email&
      state=jAy-state1-gM4fdZdV22nqm6Q_jAy-XwpYdYFh..2nqm6Q
    ```
    </details>

   At your `redirect_uri`, handle the callback to exchange the code for the user profile. Ensure this URL is registered as an Allowed Callback URI in the dashboard.
**Headless passwordless authentication:** You can implement passwordless authentication without relying on Scalekit's hosted login pages. This approach lets you build your own UI for collecting verification codes or handling magic links, giving you complete control over the user experience.

   [Learn about headless passwordless implementation](/passwordless/quickstart)

4. ## Get user details from the callback

   Scalekit redirects to your `redirect_uri` with an authorization code. Exchange it server-side for the user's profile.
**Validation attempt limits:** To protect your application, Scalekit limits a user to **five** attempts to enter the correct OTP within a ten-minute window for each authentication request.
     If the user exceeds this limit, they must restart the authentication process.

   Always perform the code exchange on the server to validate the code and return the authenticated user's profile.

    ```javascript showLineNumbers wrap title="Fetch user profile"
    // Handle oauth redirect_url, fetch code and error_description from request params
    const { code, error, error_description } = req.query;

    if (error) {
      // Handle errors
    }

    const result = await scalekit.authenticateWithCode(code, redirectUri);
    const userEmail = result.user.email;

    // Next step: create a session for this user and allow access
    ```

    ```py showLineNumbers title="Fetch user profile"
    # Handle oauth redirect_url, fetch code and error_description from request params
    code = request.args.get('code')
    error = request.args.get('error')
    error_description = request.args.get('error_description')

    if error:
        raise Exception(error_description)

    result = scalekit.authenticate_with_code(code, '<redirect_uri>')

    # result.user has the authenticated user's details
    user_email = result.user.email

    # Next step: create a session for this user and allow access
    ```

    ```go showLineNumbers title="Fetch user profile"
    // Handle oauth redirect_url, fetch code and error_description from request params
    code := r.URL.Query().Get("code")
    errorCode := r.URL.Query().Get("error")
    errorDescription := r.URL.Query().Get("error_description")

    if errorCode != "" {
      // Handle errors - include errorDescription for context
      return fmt.Errorf("OAuth error: %s - %s", errorCode, errorDescription)
    }

    result, err := scalekitClient.AuthenticateWithCode(r.Context(), code, redirectUrl)

    if err != nil {
      // Handle errors
    }

    // result.User has the authenticated user's details
    userEmail := result.User.Email

    // Next step: create a session for this user and allow access
    ```

    ```java showLineNumbers title="Fetch user profile" wrap
    // Handle oauth redirect_url, fetch code and error_description from request params
    String code = request.getParameter("code");
    String error = request.getParameter("error");
    String errorDescription = request.getParameter("error_description");

    if (error != null && !error.isEmpty()) {
        // Handle errors
        return;
    }

    try {
        AuthenticationResponse result = scalekit.authentication().authenticateWithCode(code, redirectUrl);
        String userEmail = result.getIdTokenClaims().getEmail();

        // Next step: create a session for this user and allow access
    } catch (Exception e) {
        // Handle errors
    }
    ```

    The `result` object

    ```js showLineNumbers=false wrap
        {
          user: {
            email: "john.doe@example.com"  // Authenticated user's email address
          },
          idToken: "<USER_PROFILE_JWT>",   // ID token (JWT) containing user profile claims
          accessToken: "<API_CALL_JWT>",   // Access token (JWT) for calling backend APIs on behalf of the user
          expiresIn: 899                   // Time in seconds
        }
        ```
      ```json showLineNumbers=false
        {
          "alg": "RS256",
          "kid": "snk_82937465019283746",
          "typ": "JWT"
        }.{
          "amr": [
            "conn_92847563920187364"
          ],
          "at_hash": "j8kqPm3nRt5Kx2Vy9wL_Zp",
          "aud": [
            "skc_73645291837465928"
          ],
          "azp": "skc_73645291837465928",
          "c_hash": "Hy4k2M9pWnX7vqR8_Jt3bg",
          "client_id": "skc_73645291837465928",
          "email": "alice.smith@example.com",
          "email_verified": true,
          "exp": 1751697469,
          "iat": 1751438269,
          "iss": "https://demo-company-dev.scalekit.cloud",
          "sid": "ses_83746592018273645",
          "sub": "conn_92847563920187364;alice.smith@example.com" // A scalekit user ID is sent if user management is enabled
        }.[Signature]
        ```
      ```json showLineNumbers=false
        {
          "alg": "RS256",
          "kid": "snk_794467716206433",
          "typ": "JWT"
        }.{
          "iss": "https://acme-corp-dev.scalekit.cloud",
          "sub": "conn_794467724427269;robert.wilson@acme.com",
          "aud": [
            "skc_794467724259497"
          ],
          "exp": 1751439169,
          "iat": 1751438269,
          "nbf": 1751438269,
          "client_id": "skc_794467724259497",
          "jti": "tkn_794754665320942",
          // External identifiers if updated on Scalekit
          "xoid": "ext_org_123", // Organization ID
          "xuid": "ext_usr_456"  // User ID
        }.[Signature]
        ```
      Congratulations! Your application now supports passwordless authentication. Users can sign in securely by:

 - Entering a verification code sent to their email
 - Clicking a magic link sent to their email

 To complete the implementation, [create a session](/authenticate/fsa/manage-session/) for the user to allow access to protected resources.

---

## More Scalekit documentation

| Resource | What it contains | When to use it |
|----------|-----------------|----------------|
| [/llms.txt](/llms.txt) | Structured index with routing hints per product area | Start here — find which documentation set covers your topic before loading full content |
| [/llms-full.txt](/llms-full.txt) | Complete documentation for all Scalekit products in one file | Use when you need exhaustive context across multiple products or when the topic spans several areas |
| [sitemap-0.xml](https://docs.scalekit.com/sitemap-0.xml) | Full URL list of every documentation page | Use to discover specific page URLs you can fetch for targeted, page-level answers |
