Skip to content

Commit ba54cd8

Browse files
WIP
1 parent 84867be commit ba54cd8

File tree

4 files changed

+90
-9
lines changed

4 files changed

+90
-9
lines changed

packages/nextjs/src/app-router/server/auth.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { AuthObject } from '@clerk/backend';
2-
import { constants, createClerkRequest, createRedirect, type RedirectFun } from '@clerk/backend/internal';
2+
import type { RedirectFun, SignedInAuthObject, SignedOutAuthObject } from '@clerk/backend/internal';
3+
import { constants, createClerkRequest, createRedirect } from '@clerk/backend/internal';
34
import { notFound, redirect } from 'next/navigation';
45

56
import { PUBLISHABLE_KEY, SIGN_IN_URL, SIGN_UP_URL } from '../../server/constants';
@@ -12,18 +13,33 @@ import { buildRequestLike } from './utils';
1213

1314
type Auth = AuthObject & { redirectToSignIn: RedirectFun<ReturnType<typeof redirect>> };
1415

16+
type MachineAuth = Exclude<AuthObject, SignedInAuthObject | SignedOutAuthObject> & {
17+
redirectToSignIn: RedirectFun<ReturnType<typeof redirect>>;
18+
};
19+
20+
type AuthOptions = { entity?: 'user' | 'machine' };
21+
1522
export interface AuthFn {
1623
(): Promise<Auth>;
1724
protect: AuthProtect;
1825
}
1926

20-
export const auth: AuthFn = async () => {
27+
export interface MachineAuthFn {
28+
(options?: AuthOptions): Promise<MachineAuth>;
29+
protect: AuthProtect;
30+
}
31+
32+
export function auth(options?: AuthOptions & { entity: 'user' }): Promise<Auth>;
33+
export function auth(options?: AuthOptions & { entity: 'machine' }): Promise<MachineAuth>;
34+
export async function auth(options?: AuthOptions): Promise<Auth>;
35+
export async function auth(options?: AuthOptions) {
2136
require('server-only');
2237

2338
const request = await buildRequestLike();
2439
const authObject = createGetAuth({
2540
debugLoggerName: 'auth()',
2641
noAuthStatusMessage: authAuthHeaderMissing(),
42+
options,
2743
})(request);
2844

2945
const clerkUrl = getAuthKeyFromRequest(request, 'ClerkUrl');
@@ -50,7 +66,7 @@ export const auth: AuthFn = async () => {
5066
};
5167

5268
return Object.assign(authObject, { redirectToSignIn });
53-
};
69+
}
5470

5571
auth.protect = async (...args: any[]) => {
5672
require('server-only');

packages/nextjs/src/server/clerkMiddleware.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { AuthObject, ClerkClient } from '@clerk/backend';
22
import type { AuthenticateRequestOptions, ClerkRequest, RedirectFun, RequestState } from '@clerk/backend/internal';
33
import { AuthStatus, constants, createClerkRequest, createRedirect } from '@clerk/backend/internal';
4+
import { decodeJwt } from '@clerk/backend/jwt';
45
import { eventMethodCalled } from '@clerk/shared/telemetry';
56
import { notFound as nextjsNotFound } from 'next/navigation';
67
import type { NextMiddleware, NextRequest } from 'next/server';
@@ -131,6 +132,13 @@ export const clerkMiddleware: ClerkMiddleware = (...args: unknown[]) => {
131132
logger.enable();
132133
}
133134
const clerkRequest = createClerkRequest(request);
135+
const headers = JSON.parse(clerkRequest.toJSON().headers);
136+
const authorization = headers.authorization;
137+
if (authorization) {
138+
const bearerToken = decodeJwt(authorization.split(' ')[1]);
139+
const { payload } = bearerToken;
140+
payload.sub.startsWith('mch_') ? (options.entity = 'machine') : null;
141+
}
134142
logger.debug('options', options);
135143
logger.debug('url', () => clerkRequest.toJSON());
136144

packages/nextjs/src/server/createGetAuth.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,30 @@
11
import type { AuthObject } from '@clerk/backend';
2+
import type {
3+
AuthenticatedMachineObject,
4+
SignedInAuthObject,
5+
SignedOutAuthObject,
6+
UnauthenticatedMachineObject,
7+
} from '@clerk/backend/internal';
28
import { constants } from '@clerk/backend/internal';
39
import { decodeJwt } from '@clerk/backend/jwt';
410
import { isTruthy } from '@clerk/shared/underscore';
511

612
import { withLogger } from '../utils/debugLogger';
7-
import { getAuthDataFromRequest } from './data/getAuthDataFromRequest';
13+
import type { GetAuthDataFromRequestOptions } from './data/getAuthDataFromRequest';
14+
import { getAuthDataFromRequest as getAuthDataFromRequestOriginal } from './data/getAuthDataFromRequest';
815
import { getAuthAuthHeaderMissing } from './errors';
916
import type { RequestLike } from './types';
1017
import { assertAuthStatus, getCookie, getHeader } from './utils';
1118

19+
type GetAuthOptions = { entity?: 'user' | 'machine' };
1220
export const createGetAuth = ({
1321
noAuthStatusMessage,
1422
debugLoggerName,
23+
options,
1524
}: {
1625
debugLoggerName: string;
1726
noAuthStatusMessage: string;
27+
options?: GetAuthOptions;
1828
}) =>
1929
withLogger(debugLoggerName, logger => {
2030
return (req: RequestLike, opts?: { secretKey?: string }): AuthObject => {
@@ -24,7 +34,21 @@ export const createGetAuth = ({
2434

2535
assertAuthStatus(req, noAuthStatusMessage);
2636

27-
return getAuthDataFromRequest(req, { ...opts, logger });
37+
// Explicitly declare overloads at the top level
38+
function getAuthDataFromRequest(
39+
req: RequestLike,
40+
opts: GetAuthDataFromRequestOptions & { entity: 'machine' },
41+
): Exclude<AuthObject, SignedInAuthObject | SignedOutAuthObject>;
42+
function getAuthDataFromRequest(
43+
req: RequestLike,
44+
opts: GetAuthDataFromRequestOptions & { entity: 'user' },
45+
): Exclude<AuthObject, AuthenticatedMachineObject | UnauthenticatedMachineObject>;
46+
function getAuthDataFromRequest(req: RequestLike, opts: GetAuthDataFromRequestOptions): AuthObject;
47+
function getAuthDataFromRequest(req: RequestLike, opts: GetAuthDataFromRequestOptions) {
48+
// Ensure you spread and pass the correct options, including the logger
49+
return getAuthDataFromRequestOriginal(req, { ...opts, logger, entity: options?.entity });
50+
}
51+
return getAuthDataFromRequest(req, { ...opts, logger, entity: options?.entity });
2852
};
2953
});
3054

packages/nextjs/src/server/data/getAuthDataFromRequest.ts

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
import type { AuthObject } from '@clerk/backend';
2-
import { AuthStatus, constants, signedInAuthObject, signedOutAuthObject } from '@clerk/backend/internal';
2+
import type {
3+
AuthenticatedMachineObject,
4+
SignedInAuthObject,
5+
SignedOutAuthObject,
6+
UnauthenticatedMachineObject,
7+
} from '@clerk/backend/internal';
8+
import {
9+
authenticatedMachineObject,
10+
AuthStatus,
11+
constants,
12+
signedInAuthObject,
13+
signedOutAuthObject,
14+
unauthenticatedMachineObject,
15+
} from '@clerk/backend/internal';
316
import { decodeJwt } from '@clerk/backend/jwt';
417

518
import type { LoggerNoCommit } from '../../utils/debugLogger';
@@ -11,10 +24,21 @@ import { assertTokenSignature, decryptClerkRequestData, getAuthKeyFromRequest, g
1124
* Given a request object, builds an auth object from the request data. Used in server-side environments to get access
1225
* to auth data for a given request.
1326
*/
27+
export type GetAuthDataFromRequestOptions = {
28+
secretKey?: string;
29+
logger?: LoggerNoCommit;
30+
entity?: 'user' | 'machine';
31+
};
1432
export function getAuthDataFromRequest(
1533
req: RequestLike,
16-
opts: { secretKey?: string; logger?: LoggerNoCommit } = {},
17-
): AuthObject {
34+
opts: GetAuthDataFromRequestOptions & { entity: 'machine' },
35+
): Exclude<AuthObject, SignedInAuthObject | SignedOutAuthObject>;
36+
export function getAuthDataFromRequest(
37+
req: RequestLike,
38+
opts: GetAuthDataFromRequestOptions & { entity: 'user' },
39+
): Exclude<AuthObject, AuthenticatedMachineObject | UnauthenticatedMachineObject>;
40+
export function getAuthDataFromRequest(req: RequestLike, opts?: GetAuthDataFromRequestOptions): AuthObject;
41+
export function getAuthDataFromRequest(req: RequestLike, opts: GetAuthDataFromRequestOptions = {}) {
1842
const authStatus = getAuthKeyFromRequest(req, 'AuthStatus');
1943
const authToken = getAuthKeyFromRequest(req, 'AuthToken');
2044
const authMessage = getAuthKeyFromRequest(req, 'AuthMessage');
@@ -39,7 +63,16 @@ export function getAuthDataFromRequest(
3963
opts.logger?.debug('auth options', options);
4064

4165
let authObject;
42-
if (!authStatus || authStatus !== AuthStatus.SignedIn) {
66+
if (opts.entity === 'machine' && (!authStatus || authStatus !== AuthStatus.MachineAuthenticated)) {
67+
authObject = unauthenticatedMachineObject(options);
68+
} else if (opts.entity === 'machine' && authStatus === AuthStatus.MachineAuthenticated) {
69+
assertTokenSignature(authToken as string, options.secretKey, authSignature);
70+
71+
const jwt = decodeJwt(authToken as string);
72+
73+
opts.logger?.debug('jwt', jwt.raw);
74+
authObject = authenticatedMachineObject(jwt.raw.text, jwt.payload);
75+
} else if (!authStatus || authStatus !== AuthStatus.SignedIn) {
4376
authObject = signedOutAuthObject(options);
4477
} else {
4578
assertTokenSignature(authToken as string, options.secretKey, authSignature);

0 commit comments

Comments
 (0)