mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
Address review: clarify requiredScopes fail-open semantics, simplify scope dedup, make ALL_SCOPES readonly
Co-Authored-By: mantra <mantra@stack-auth.com>
This commit is contained in:
parent
2fd0801e0a
commit
f18255b6fa
@ -443,7 +443,7 @@ export async function createRefreshTokenObj(options: CreateRefreshTokenOptions)
|
||||
|
||||
const refreshToken = generateSecureRandomString();
|
||||
|
||||
const scopes = options.scopes ? parseScopeString(scopesToString(options.scopes)) : [];
|
||||
const scopes = options.scopes ? [...new Set(options.scopes)] : [];
|
||||
|
||||
const refreshTokenObj = await globalPrismaClient.projectUserRefreshToken.create({
|
||||
data: {
|
||||
|
||||
@ -27,8 +27,16 @@ type ShownEndpointDocumentation = {
|
||||
description: string,
|
||||
tags?: string[],
|
||||
crudOperation?: Capitalize<CrudlOperation>,
|
||||
// Scopes a client access token must hold to call this endpoint. Enforced centrally in the
|
||||
// smart route handler (server/admin keys bypass). See `packages/stack-shared/src/scopes.ts`.
|
||||
// Scopes that a *scoped* client access token must hold to call this endpoint. Enforced centrally
|
||||
// in the smart route handler. See `packages/stack-shared/src/scopes.ts`.
|
||||
//
|
||||
// IMPORTANT — this is an opt-in *down-scoping* restriction, NOT a security boundary. The check is
|
||||
// fail-open: server/admin secret keys bypass entirely, and a client token that carries no `scope`
|
||||
// claim (every token minted before scopes existed, and any session created without an explicit
|
||||
// `scope`) is treated as unrestricted and reaches the handler regardless of this field. Only
|
||||
// tokens that explicitly declare scopes are constrained to the scopes they list. Do NOT rely on
|
||||
// `requiredScopes` to keep callers out of an endpoint — use access type / permissions for that.
|
||||
//
|
||||
// Omitted / undefined means "no scope required". An empty array means the same, but documents
|
||||
// that the absence of a requirement was deliberate (useful for the scope-coverage test).
|
||||
requiredScopes?: Scope[],
|
||||
|
||||
@ -30,7 +30,7 @@ export const SCOPES = {
|
||||
|
||||
export type Scope = keyof typeof SCOPES;
|
||||
|
||||
export const ALL_SCOPES = Object.keys(SCOPES) as Scope[];
|
||||
export const ALL_SCOPES: readonly Scope[] = Object.keys(SCOPES) as Scope[];
|
||||
|
||||
export function isScope(value: string): value is Scope {
|
||||
return Object.prototype.hasOwnProperty.call(SCOPES, value);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user