> **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>`: `agentkit`, `full-stack-auth`, `mcp-auth`, `modular-sso`, `modular-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
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.

##  Review the authentication sequence

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

```

### [Build with a coding agent](/dev-kit/build-with-ai/full-stack-auth/)

### Claude Code

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

   ### GitHub Copilot CLI

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

   ### 40+ agents

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

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

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 showLineNumbers wrap
import { ScalekitClient } from '@scalekit-sdk/node';
// Initialize the SDK client
const scalekit = new ScalekitClient(
  '',
  '',
  '',
);

const options = {};

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

const authorizationUrl = scalekit.getAuthorizationUrl(redirectUri, options);
// Generated URL will look like:
// https:///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 showLineNumbers wrap
from scalekit import ScalekitClient, AuthorizationUrlOptions, CodeAuthenticationOptions

# Initialize the SDK client
scalekit = ScalekitClient(
  '',
  '',
  ''
)

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:///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 showLineNumbers
import (
  "github.com/scalekit-inc/scalekit-sdk-go"
)

func main() {
  // Initialize the SDK client
  scalekitClient := scalekit.NewScalekitClient(
    "",
    "",
    ""
  )

  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 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(
      "",
      "",
      ""
    );
    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"
    /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 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
```

    ### Python

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

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

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

    
      ### Result object

```js showLineNumbers=false wrap
{
  user: {
    email: "john.doe@example.com"  // Authenticated user's email address
  },
  idToken: "",   // ID token (JWT) containing user profile claims
  accessToken: "",   // Access token (JWT) for calling backend APIs on behalf of the user
  expiresIn: 899                   // Time in seconds
}
```

      ### Decoded ID token

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

       ### Decoded access token

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