import express from 'express' ; import RateLimit from 'express-rate-limit' ; import { logger } from '@server/helpers/logger' ; import { CONFIG } from '@server/initializers/config' ; import { getAuthNameFromRefreshGrant , getBypassFromExternalAuth , getBypassFromPasswordGrant } from '@server/lib/auth/external-auth' ; import { handleOAuthToken } from '@server/lib/auth/oauth' ; import { BypassLogin , revokeToken } from '@server/lib/auth/oauth-model' ; import { Hooks } from '@server/lib/plugins/hooks' ; import { asyncMiddleware , authenticate , openapiOperationDoc } from '@server/middlewares' ; import { buildUUID } from '@shared/extra-utils' ; import { ScopedToken } from '@shared/models/users/user-scoped-token' ; const tokensRouter = express . Router ( ) ; const loginRateLimiter = RateLimit ( { windowMs : CONFIG . RATES_LIMIT . LOGIN . WINDOW_MS , max : CONFIG . RATES_LIMIT . LOGIN . MAX } ) ; tokensRouter . post ( '/token' , loginRateLimiter , openapiOperationDoc ( { operationId : 'getOAuthToken' } ) , asyncMiddleware ( handleToken ) ) ; tokensRouter . post ( '/revoke-token' , openapiOperationDoc ( { operationId : 'revokeOAuthToken' } ) , authenticate , asyncMiddleware ( handleTokenRevocation ) ) ; tokensRouter . get ( '/scoped-tokens' , authenticate , getScopedTokens ) ; tokensRouter . post ( '/scoped-tokens' , authenticate , asyncMiddleware ( renewScopedTokens ) ) ; export { tokensRouter } ; async function handleToken ( req , res , next ) { const grantType = req . body . grant_type ; try { const bypassLogin = await buildByPassLogin ( req , grantType ) ; const refreshTokenAuthName = grantType === 'refresh_token' ? await getAuthNameFromRefreshGrant ( req . body . refresh_token ) : undefined ; const options = { refreshTokenAuthName , bypassLogin } ; const token = await handleOAuthToken ( req , options ) ; res . set ( 'Cache-Control' , 'no-store' ) ; res . set ( 'Pragma' , 'no-cache' ) ; Hooks . runAction ( 'action:api.user.oauth2-got-token' , { username : token . user . username , ip : req . ip , req , res } ) ; return res . json ( { token_type : 'Bearer' , access_token : token . accessToken , refresh_token : token . refreshToken , expires_in : token . accessTokenExpiresIn , refresh_token_expires_in : token . refreshTokenExpiresIn } ) ; } catch ( err ) { logger . warn ( 'Login error' , { err } ) ; return res . fail ( { status : err . code , message : err . message , type : err . name } ) ; } } async function handleTokenRevocation ( req , res ) { const token = res . locals . oauth . token ; const result = await revokeToken ( token , { req , explicitLogout : true } ) ; return res . json ( result ) ; } function getScopedTokens ( req , res ) { const user = res . locals . oauth . token . user ; return res . json ( { feedToken : user . feedToken } as ScopedToken ) ; } async function renewScopedTokens ( req , res ) { const user = res . locals . oauth . token . user ; user . feedToken = buildUUID ( ) ; await user . save ( ) ; return res . json ( { feedToken : user . feedToken } as ScopedToken ) ; } async function buildByPassLogin ( req , grantType ) { if ( grantType !== 'password' ) return undefined ; if ( req . body . externalAuthToken ) { return getBypassFromExternalAuth ( req . body . username , req . body . externalAuthToken ) ; } return getBypassFromPasswordGrant ( req . body . username , req . body . password ) ; }