Skip to content

Commit 3de7ca7

Browse files
feat: add Scalekit SSO provider
Scalekit is an enterprise SSO platform (SAML, OIDC, social login) that exposes a single OIDC-compliant interface. Auth.js auto-discovers all endpoints from the issuer URL via .well-known/openid-configuration. Supports flexible SSO routing via connectionId, organizationId, or domain.
1 parent f457068 commit 3de7ca7

5 files changed

Lines changed: 362 additions & 0 deletions

File tree

.github/ISSUE_TEMPLATE/2_bug_provider.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ body:
8787
- "Reddit"
8888
- "Roblox"
8989
- "Salesforce"
90+
- "Scalekit"
9091
- "SimpleLogin"
9192
- "Slack"
9293
- "Spotify"
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
import { Callout } from "nextra/components"
2+
import { Code } from "@/components/Code"
3+
4+
<img align="right" src="/img/providers/scalekit.png" height="64" width="64" />
5+
6+
# Scalekit Provider
7+
8+
## Resources
9+
10+
- [Scalekit Single Sign-On documentation](https://docs.scalekit.com/sso/quickstart)
11+
- [Scalekit OIDC documentation](https://docs.scalekit.com/sso/oidc)
12+
13+
## Setup
14+
15+
### Callback URL
16+
17+
<Code>
18+
<Code.Next>
19+
20+
```bash
21+
https://example.com/api/auth/callback/scalekit
22+
```
23+
24+
</Code.Next>
25+
<Code.Qwik>
26+
27+
```bash
28+
https://example.com/auth/callback/scalekit
29+
```
30+
31+
</Code.Qwik>
32+
<Code.Svelte>
33+
34+
```bash
35+
https://example.com/auth/callback/scalekit
36+
```
37+
38+
</Code.Svelte>
39+
<Code.Express>
40+
41+
```bash
42+
https://example.com/auth/callback/scalekit
43+
```
44+
45+
</Code.Express>
46+
</Code>
47+
48+
### Environment Variables
49+
50+
```
51+
AUTH_SCALEKIT_ID
52+
AUTH_SCALEKIT_SECRET
53+
AUTH_SCALEKIT_ISSUER
54+
```
55+
56+
`AUTH_SCALEKIT_ISSUER` is your Scalekit environment URL (e.g. `https://yourenv.scalekit.dev`).
57+
58+
### Configuration
59+
60+
<Code>
61+
<Code.Next>
62+
63+
```ts filename="/auth.ts"
64+
import NextAuth from "next-auth"
65+
import Scalekit from "next-auth/providers/scalekit"
66+
67+
export const { handlers, auth, signIn, signOut } = NextAuth({
68+
providers: [Scalekit],
69+
})
70+
```
71+
72+
</Code.Next>
73+
<Code.Qwik>
74+
75+
```ts filename="/src/routes/[email protected]"
76+
import { QwikAuth$ } from "@auth/qwik"
77+
import Scalekit from "@auth/qwik/providers/scalekit"
78+
79+
export const { onRequest, useSession, useSignIn, useSignOut } = QwikAuth$(
80+
() => ({
81+
providers: [Scalekit],
82+
})
83+
)
84+
```
85+
86+
</Code.Qwik>
87+
<Code.Svelte>
88+
89+
```ts filename="/src/auth.ts"
90+
import { SvelteKitAuth } from "@auth/sveltekit"
91+
import Scalekit from "@auth/sveltekit/providers/scalekit"
92+
93+
export const { handle, signIn, signOut } = SvelteKitAuth({
94+
providers: [Scalekit],
95+
})
96+
```
97+
98+
</Code.Svelte>
99+
<Code.Express>
100+
101+
```ts filename="/src/app.ts"
102+
import { ExpressAuth } from "@auth/express"
103+
import Scalekit from "@auth/express/providers/scalekit"
104+
105+
app.use("/auth/*", ExpressAuth({ providers: [Scalekit] }))
106+
```
107+
108+
</Code.Express>
109+
</Code>
110+
111+
### SSO Routing
112+
113+
Scalekit supports multiple ways to route users to their SSO connection. You can pass optional routing parameters to target a specific connection:
114+
115+
<Code>
116+
<Code.Next>
117+
118+
```ts filename="/auth.ts"
119+
import NextAuth from "next-auth"
120+
import Scalekit from "next-auth/providers/scalekit"
121+
122+
export const { handlers, auth, signIn, signOut } = NextAuth({
123+
providers: [
124+
Scalekit({
125+
// pick one of the following routing strategies:
126+
connectionId: "conn_...", // exact connection (highest precedence)
127+
organizationId: "org_...", // org's active SSO connection
128+
domain: "acme.com", // resolve org from email domain
129+
}),
130+
],
131+
})
132+
```
133+
134+
</Code.Next>
135+
<Code.Qwik>
136+
137+
```ts filename="/src/routes/[email protected]"
138+
import { QwikAuth$ } from "@auth/qwik"
139+
import Scalekit from "@auth/qwik/providers/scalekit"
140+
141+
export const { onRequest, useSession, useSignIn, useSignOut } = QwikAuth$(
142+
() => ({
143+
providers: [
144+
Scalekit({
145+
connectionId: "conn_...",
146+
organizationId: "org_...",
147+
domain: "acme.com",
148+
}),
149+
],
150+
})
151+
)
152+
```
153+
154+
</Code.Qwik>
155+
<Code.Svelte>
156+
157+
```ts filename="/src/auth.ts"
158+
import { SvelteKitAuth } from "@auth/sveltekit"
159+
import Scalekit from "@auth/sveltekit/providers/scalekit"
160+
161+
export const { handle, signIn, signOut } = SvelteKitAuth({
162+
providers: [
163+
Scalekit({
164+
connectionId: "conn_...",
165+
organizationId: "org_...",
166+
domain: "acme.com",
167+
}),
168+
],
169+
})
170+
```
171+
172+
</Code.Svelte>
173+
<Code.Express>
174+
175+
```ts filename="/src/app.ts"
176+
import { ExpressAuth } from "@auth/express"
177+
import Scalekit from "@auth/express/providers/scalekit"
178+
179+
app.use(
180+
"/auth/*",
181+
ExpressAuth({
182+
providers: [
183+
Scalekit({
184+
connectionId: "conn_...",
185+
organizationId: "org_...",
186+
domain: "acme.com",
187+
}),
188+
],
189+
})
190+
)
191+
```
192+
193+
</Code.Express>
194+
</Code>
195+
196+
<Callout>
197+
Scalekit is an OIDC-compliant platform — Auth.js automatically discovers all
198+
endpoints from your `AUTH_SCALEKIT_ISSUER` URL via
199+
`/.well-known/openid-configuration`. No manual endpoint configuration is
200+
required.
201+
</Callout>
2.84 KB
Loading

lefthook.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ pre-commit:
22
parallel: true
33
commands:
44
format:
5+
glob: "*.{ts,tsx,js,mjs,cjs,json,md,mdx,svelte,yml,yaml}"
56
run: pnpm prettier --cache --write {staged_files}
67
stage_fixed: true
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/**
2+
* <div class="provider" style={{backgroundColor: "#1c1c1e", display: "flex", justifyContent: "space-between", color: "#fff", padding: 16}}>
3+
* <span>Built-in <b>Scalekit</b> integration.</span>
4+
* <a href="https://scalekit.com/">
5+
* <img style={{display: "block"}} src="https://authjs.dev/img/providers/scalekit.png" height="48" />
6+
* </a>
7+
* </div>
8+
*
9+
* @module providers/scalekit
10+
*/
11+
import type { OIDCConfig, OAuthUserConfig } from "./index.js"
12+
13+
/**
14+
* The profile returned by Scalekit's userinfo endpoint.
15+
*
16+
* - {@link https://docs.scalekit.com/apis/userinfo | Scalekit UserInfo endpoint}
17+
*/
18+
export interface ScalekitProfile extends Record<string, any> {
19+
/** Unique user ID (`usr_...`) */
20+
sub: string
21+
email: string
22+
email_verified: boolean
23+
name: string
24+
given_name: string
25+
family_name: string
26+
picture: string
27+
/** Organization ID (`org_...`) */
28+
oid: string
29+
}
30+
31+
/**
32+
* Add Scalekit SSO login to your page.
33+
*
34+
* ### Setup
35+
*
36+
* #### Callback URL
37+
* ```
38+
* https://example.com/api/auth/callback/scalekit
39+
* ```
40+
*
41+
* #### Configuration
42+
* ```ts
43+
* import { Auth } from "@auth/core"
44+
* import Scalekit from "@auth/core/providers/scalekit"
45+
*
46+
* const request = new Request(origin)
47+
* const response = await Auth(request, {
48+
* providers: [
49+
* Scalekit({
50+
* clientId: AUTH_SCALEKIT_ID,
51+
* clientSecret: AUTH_SCALEKIT_SECRET,
52+
* issuer: AUTH_SCALEKIT_ISSUER,
53+
* }),
54+
* ],
55+
* })
56+
* ```
57+
*
58+
* ### Resources
59+
*
60+
* - [Scalekit Single Sign-On documentation](https://docs.scalekit.com/sso/quickstart)
61+
* - [Scalekit OIDC documentation](https://docs.scalekit.com/sso/oidc)
62+
*
63+
* ### SSO Routing
64+
*
65+
* Scalekit supports multiple ways to route a user to their SSO connection.
66+
* Pass one of the following optional parameters to target a specific connection:
67+
*
68+
* ```ts
69+
* Scalekit({
70+
* clientId: AUTH_SCALEKIT_ID,
71+
* clientSecret: AUTH_SCALEKIT_SECRET,
72+
* issuer: AUTH_SCALEKIT_ISSUER,
73+
* // pick one of the following routing strategies:
74+
* connectionId: "conn_...", // exact connection (highest precedence)
75+
* organizationId: "org_...", // org's active SSO connection
76+
* domain: "acme.com", // resolve org from email domain
77+
* })
78+
* ```
79+
*
80+
* ### Notes
81+
*
82+
* By default, Auth.js assumes that the Scalekit provider is
83+
* based on the [Open ID Connect](https://openid.net/specs/openid-connect-core-1_0.html) specification.
84+
*
85+
* Scalekit is an enterprise SSO platform that supports SAML, OIDC, and social login
86+
* (Google, Microsoft, GitHub, etc.) connections. It exposes a single OIDC-compliant
87+
* interface, so Auth.js auto-discovers all endpoints from the issuer URL via
88+
* `/.well-known/openid-configuration` — no manual endpoint configuration required.
89+
*
90+
* Each Scalekit environment has a unique issuer URL of the form
91+
* `https://<subdomain>.scalekit.dev` (dev) or `https://<subdomain>.scalekit.com` (prod).
92+
* Set `AUTH_SCALEKIT_ISSUER` to this URL.
93+
*
94+
* :::tip
95+
*
96+
* The Scalekit provider comes with a [default configuration](https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/providers/scalekit.ts).
97+
* To override the defaults for your use case, check out [customizing a built-in OAuth provider](https://authjs.dev/guides/configuring-oauth-providers).
98+
*
99+
* :::
100+
*
101+
* :::info **Disclaimer**
102+
*
103+
* If you think you found a bug in the default configuration, you can [open an issue](https://authjs.dev/new/provider-issue).
104+
*
105+
* Auth.js strictly adheres to the specification and it cannot take responsibility for any deviation from
106+
* the spec by the provider. You can open an issue, but if the problem is non-compliance with the spec,
107+
* we might not pursue a resolution. You can ask for more help in [Discussions](https://authjs.dev/new/github-discussions).
108+
*
109+
* :::
110+
*/
111+
export default function Scalekit<P extends ScalekitProfile>(
112+
options: OAuthUserConfig<P> & {
113+
/**
114+
* Your Scalekit environment URL (e.g. `https://yourenv.scalekit.dev`).
115+
* Used for OIDC discovery and as the token issuer.
116+
*/
117+
issuer: string
118+
/**
119+
* Route the user to a specific SSO connection by its ID (`conn_...`).
120+
* Takes precedence over `organizationId` and `domain`.
121+
*/
122+
connectionId?: string
123+
/**
124+
* Route the user to a specific organization's active SSO connection (`org_...`).
125+
*/
126+
organizationId?: string
127+
/**
128+
* Route the user to the SSO connection associated with this email domain.
129+
*/
130+
domain?: string
131+
}
132+
): OIDCConfig<P> {
133+
const { issuer, connectionId, organizationId, domain } = options
134+
135+
return {
136+
id: "scalekit",
137+
name: "Scalekit",
138+
type: "oidc",
139+
issuer,
140+
authorization: {
141+
params: {
142+
scope: "openid email profile",
143+
...(connectionId && { connection_id: connectionId }),
144+
...(organizationId && { organization_id: organizationId }),
145+
...(domain && { domain }),
146+
},
147+
},
148+
profile(profile) {
149+
return {
150+
id: profile.sub,
151+
name: profile.name ?? `${profile.given_name} ${profile.family_name}`,
152+
email: profile.email,
153+
image: profile.picture ?? null,
154+
}
155+
},
156+
style: { bg: "#1c1c1e", text: "#fff" },
157+
options,
158+
}
159+
}

0 commit comments

Comments
 (0)