-
Notifications
You must be signed in to change notification settings - Fork 353
feat(express,fastify,tanstack-react-start,react-router): Support machine auth tokens in getAuth()
#6067
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(express,fastify,tanstack-react-start,react-router): Support machine auth tokens in getAuth()
#6067
Changes from all commits
22a895d
2c85eb8
2c2d3db
662f1b2
a560b34
32e75a0
509ed81
09d4304
83fbbc9
6e7a5b2
a138472
d91ad25
a925e4d
4b3ee91
c220a63
2a4648e
88db02d
d4dd19d
e597656
4c9d741
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'@clerk/backend': patch | ||
'@clerk/nextjs': patch | ||
--- | ||
|
||
Re-organize internal types for the recently added "machine authentication" feature. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
--- | ||
'@clerk/tanstack-react-start': minor | ||
--- | ||
|
||
Introduces machine authentication, supporting four token types: `api_key`, `oauth_token`, `machine_token`, and `session_token`. For backwards compatibility, `session_token` remains the default when no token type is specified. This enables machine-to-machine authentication and use cases such as API keys and OAuth integrations. Existing applications continue to work without modification. | ||
|
||
You can specify which token types are allowed by using the `acceptsToken` option in the `getAuth()` function. This option can be set to a specific type, an array of types, or `'any'` to accept all supported tokens. | ||
|
||
Example usage: | ||
|
||
```ts | ||
import { createServerFn } from '@tanstack/react-start' | ||
import { getAuth } from '@clerk/tanstack-react-start/server' | ||
import { getWebRequest } from '@tanstack/react-start/server' | ||
|
||
const authStateFn = createServerFn({ method: 'GET' }).handler(async () => { | ||
const request = getWebRequest() | ||
const auth = await getAuth(request, { acceptsToken: 'any' }) | ||
|
||
if (authObject.tokenType === 'session_token') { | ||
console.log('this is session token from a user') | ||
} else { | ||
console.log('this is some other type of machine token') | ||
console.log('more specifically, a ' + authObject.tokenType) | ||
} | ||
|
||
return {} | ||
}) | ||
|
||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
--- | ||
'@clerk/express': minor | ||
--- | ||
|
||
Introduces machine authentication, supporting four token types: `api_key`, `oauth_token`, `machine_token`, and `session_token`. For backwards compatibility, `session_token` remains the default when no token type is specified. This enables machine-to-machine authentication and use cases such as API keys and OAuth integrations. Existing applications continue to work without modification. | ||
|
||
You can specify which token types are allowed by using the `acceptsToken` option in the `getAuth()` function. This option can be set to a specific type, an array of types, or `'any'` to accept all supported tokens. | ||
|
||
Example usage: | ||
|
||
```ts | ||
import express from 'express'; | ||
import { getAuth } from '@clerk/express'; | ||
|
||
const app = express(); | ||
|
||
app.get('/path', (req, res) => { | ||
const authObject = getAuth(req, { acceptsToken: 'any' }); | ||
|
||
if (authObject.tokenType === 'session_token') { | ||
console.log('this is session token from a user') | ||
} else { | ||
console.log('this is some other type of machine token') | ||
console.log('more specifically, a ' + authObject.tokenType) | ||
} | ||
}); | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
--- | ||
'@clerk/react-router': minor | ||
--- | ||
|
||
Introduces machine authentication, supporting four token types: `api_key`, `oauth_token`, `machine_token`, and `session_token`. For backwards compatibility, `session_token` remains the default when no token type is specified. This enables machine-to-machine authentication and use cases such as API keys and OAuth integrations. Existing applications continue to work without modification. | ||
|
||
You can specify which token types are allowed by using the `acceptsToken` option in the `getAuth()` function. This option can be set to a specific type, an array of types, or `'any'` to accept all supported tokens. | ||
|
||
Example usage: | ||
|
||
```ts | ||
import { getAuth } from '@clerk/react-router/ssr.server' | ||
import type { Route } from './+types/profile' | ||
|
||
export async function loader(args: Route.LoaderArgs) { | ||
const authObject = await getAuth(args, { acceptsToken: 'any' }) | ||
|
||
if (authObject.tokenType === 'session_token') { | ||
console.log('this is session token from a user') | ||
} else { | ||
console.log('this is some other type of machine token') | ||
console.log('more specifically, a ' + authObject.tokenType) | ||
} | ||
|
||
return {} | ||
} | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
--- | ||
'@clerk/fastify': minor | ||
--- | ||
|
||
Introduces machine authentication, supporting four token types: `api_key`, `oauth_token`, `machine_token`, and `session_token`. For backwards compatibility, `session_token` remains the default when no token type is specified. This enables machine-to-machine authentication and use cases such as API keys and OAuth integrations. Existing applications continue to work without modification. | ||
|
||
You can specify which token types are allowed by using the `acceptsToken` option in the `getAuth()` function. This option can be set to a specific type, an array of types, or `'any'` to accept all supported tokens. | ||
|
||
Example usage: | ||
|
||
```ts | ||
import Fastify from 'fastify' | ||
import { getAuth } from '@clerk/fastify' | ||
|
||
const fastify = Fastify() | ||
|
||
fastify.get('/path', (request, reply) => { | ||
const authObject = getAuth(req, { acceptsToken: 'any' }); | ||
|
||
if (authObject.tokenType === 'session_token') { | ||
console.log('this is session token from a user') | ||
} else { | ||
console.log('this is some other type of machine token') | ||
console.log('more specifically, a ' + authObject.tokenType) | ||
} | ||
}); | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,16 +2,46 @@ import { getAuth } from '../getAuth'; | |
import { mockRequest, mockRequestWithAuth } from './helpers'; | ||
|
||
describe('getAuth', () => { | ||
it('throws error if clerkMiddleware is not executed before getAuth', async () => { | ||
it('throws error if clerkMiddleware is not executed before getAuth', () => { | ||
expect(() => getAuth(mockRequest())).toThrow(/The "clerkMiddleware" should be registered before using "getAuth"/); | ||
}); | ||
|
||
it('returns auth from request for signed-out request', async () => { | ||
expect(getAuth(mockRequestWithAuth())).toHaveProperty('userId', null); | ||
it('returns auth from request for signed-out request', () => { | ||
const req = mockRequestWithAuth({ userId: null, tokenType: 'session_token' }); | ||
const auth = getAuth(req); | ||
expect(auth.userId).toBeNull(); | ||
expect(auth.tokenType).toBe('session_token'); | ||
}); | ||
|
||
it('returns auth from request', async () => { | ||
const req = mockRequestWithAuth({ userId: 'user_12345' }); | ||
expect(getAuth(req)).toHaveProperty('userId', 'user_12345'); | ||
it('returns auth from request', () => { | ||
const req = mockRequestWithAuth({ userId: 'user_12345', tokenType: 'session_token' }); | ||
const auth = getAuth(req); | ||
expect(auth.userId).toBe('user_12345'); | ||
expect(auth.tokenType).toBe('session_token'); | ||
}); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we wanna add a test case that asserts that the default There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the actual However, the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, sorry, I misread lol. The changeset is saying what you're saying. So never mind :) |
||
it('returns the actual auth object when its tokenType matches acceptsToken', () => { | ||
const req = mockRequestWithAuth({ tokenType: 'api_key', id: 'ak_1234', subject: 'api_key_1234' }); | ||
const result = getAuth(req, { acceptsToken: 'api_key' }); | ||
expect(result.tokenType).toBe('api_key'); | ||
expect(result.id).toBe('ak_1234'); | ||
expect(result.subject).toBe('api_key_1234'); | ||
}); | ||
|
||
it('returns the actual auth object if its tokenType is included in the acceptsToken array', () => { | ||
const req = mockRequestWithAuth({ tokenType: 'machine_token', id: 'mt_1234' }); | ||
const result = getAuth(req, { acceptsToken: ['machine_token', 'api_key'] }); | ||
expect(result.tokenType).toBe('machine_token'); | ||
expect(result.id).toBe('mt_1234'); | ||
expect(result.subject).toBeUndefined(); | ||
}); | ||
|
||
it('returns an unauthenticated auth object when the tokenType does not match acceptsToken', () => { | ||
const req = mockRequestWithAuth({ tokenType: 'session_token', userId: 'user_12345' }); | ||
const result = getAuth(req, { acceptsToken: 'api_key' }); | ||
expect(result.tokenType).toBe('session_token'); // reflects the actual token found | ||
// Properties specific to authenticated objects should be null or undefined | ||
// @ts-expect-error - userId is not a property of the unauthenticated object | ||
expect(result.userId).toBeNull(); | ||
}); | ||
}); |
Uh oh!
There was an error while loading. Please reload this page.