> **Building with AI coding agents?** Install the authstack plugin with one command. This equips your agent with accurate Scalekit implementation patterns.
>
> **Recommended** (the `-y` flags skip prompts, so the command runs without an interactive terminal):
> ```bash
> npx -y @scalekit-inc/cli setup -y
> ```
>
> Global:
> ```bash
> npm install -g @scalekit-inc/cli
> scalekit setup -y
> ```
>
> Supports Claude Code, Cursor, GitHub Copilot, Codex + skills for other Agent Skills-compatible agents in `~/.agents/skills`.
> Skills: integrate-agentkit, implement-saaskit, add-mcp-oauth, implement-sso, implement-scim.
> [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# Passwordless OIDC Quickstart

Add passwordless sign-in with OTP or magic link via OIDC
Implement passwordless authentication with Scalekit over the OIDC protocol. Users verify their identity with an email verification code (OTP) or a magic link.

** Review the authentication sequence**

```d2 title="Passwordless login: the user enters an email, verifies with an OTP or magic link, and your app exchanges the code for user details"

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"

```

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.

    > Image: Scalekit dashboard Magic link & OTP settings showing the login method selection and expiry period fields

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**

    **Node.js**

    ```javascript
    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**

    ```python
    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**

    ```go
    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**

    ```java
    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.

    **Example authorization URL**

    ```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
    ```

   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.

   > note: 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
   > 

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.

   > caution: 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.

    **Node.js**

    ```javascript 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
    ```

    **Python**

    ```py 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**

    ```go 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**

    ```java title="Fetch user profile"
    // 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

      **Result object**

      ```js
      {
        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
      }
      ```

      **Decoded ID token**

      ```json
      {
        "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]
      ```

       **Decoded access token**

       ```json
       {
         "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 |
