feat(server): support refresh token (#15218)

This commit is contained in:
DarkSky
2026-07-12 02:39:42 +08:00
committed by GitHub
parent aea128f0b9
commit 02b25e05d8
80 changed files with 5866 additions and 745 deletions
@@ -18,14 +18,10 @@ import {
URLHelper,
UseNamedGuard,
} from '../../base';
import {
OAuthCallbackBodySchema,
OAuthPreflightBodySchema,
Public,
SessionIssuer,
} from '../../core/auth';
import { Public, SessionIssuer } from '../../core/auth';
import { OAuthProviderName } from './config';
import { OAuthProviderFactory } from './factory';
import { OAuthCallbackBodySchema, OAuthPreflightBodySchema } from './input';
import { OAuthService } from './service';
@Controller('/api/oauth')
@@ -48,6 +44,16 @@ export class OAuthController {
if (fields.has('client_nonce')) {
throw new MissingOauthQueryParameter({ name: 'client_nonce' });
}
if (fields.has('client')) {
throw new ActionForbidden();
}
if (fields.has('provider')) {
const provider =
body && typeof body === 'object' && 'provider' in body
? String(body.provider)
: '';
throw new UnknownOauthProvider({ name: provider });
}
throw new MissingOauthQueryParameter({ name: 'provider' });
}
@@ -0,0 +1,61 @@
import { z } from 'zod';
export const OAuthProviderSchema = z.enum([
'Google',
'GitHub',
'Apple',
'OIDC',
]);
export const OAuthClientSchema = z.enum([
'web',
'affine',
'affine-canary',
'affine-beta',
'affine-dev',
]);
export const OAuthPreflightBodySchema = z
.object({
provider: OAuthProviderSchema,
redirect_uri: z
.string()
.min(1)
.max(2048)
.nullish()
.transform(value => value ?? undefined),
client: OAuthClientSchema,
client_nonce: z.string().min(1).max(512),
})
.strict();
export const OAuthCallbackBodySchema = z
.object({
code: z.string().min(1).max(4096),
state: z.string().min(1).max(16_384),
client_nonce: z
.string()
.min(1)
.max(512)
.nullish()
.transform(value => value ?? undefined),
// Apple includes this JSON field on the first form_post callback.
user: z.string().max(16_384).optional(),
})
.strict();
export const OAuthStateEnvelopeSchema = z
.object({
state: z.string().uuid(),
provider: OAuthProviderSchema,
client: OAuthClientSchema,
flow: z.enum(['popup', 'redirect']).optional(),
pkce: z
.object({
codeChallenge: z.string().min(1).max(512),
codeChallengeMethod: z.literal('S256'),
})
.strict()
.optional(),
})
.strict();
@@ -15,12 +15,12 @@ import {
import {
AuthChallengeStore,
AuthService,
OAuthStateEnvelopeSchema,
type VerifiedIdentity,
} from '../../core/auth';
import { Models } from '../../models';
import { OAuthProviderName } from './config';
import { OAuthProviderFactory } from './factory';
import { OAuthStateEnvelopeSchema } from './input';
import { OAuthAccount, Tokens } from './providers/def';
import { OAuthPkceChallenge, OAuthState } from './types';