const authHeaderValue = this.getRequestHeaderValue()
const headers = new HttpHeaders().set('Authorization', authHeaderValue)
- this.http.post<void>(AuthService.BASE_REVOKE_TOKEN_URL, {}, { headers })
+ this.http.post<{ redirectUrl?: string }>(AuthService.BASE_REVOKE_TOKEN_URL, {}, { headers })
.subscribe(
- () => { /* nothing to do */ },
+ res => {
+ if (res.redirectUrl) {
+ window.location.href = res.redirectUrl
+ }
+ },
err => console.error(err)
)
const token = res.locals.oauth.token
res.locals.explicitLogout = true
- await revokeToken(token)
+ const result = await revokeToken(token)
// FIXME: uncomment when https://github.com/oauthjs/node-oauth2-server/pull/289 is released
// oAuthServer.revoke(req, res, err => {
// }
// })
- return res.json()
+ return res.json(result)
}
async function onExternalUserAuthenticated (options: {
return user
}
-async function revokeToken (tokenInfo: { refreshToken: string }) {
+async function revokeToken (tokenInfo: { refreshToken: string }): Promise<{ success: boolean, redirectUrl?: string }> {
const res: express.Response = this.request.res
const token = await OAuthTokenModel.getByRefreshTokenAndPopulateUser(tokenInfo.refreshToken)
if (token) {
+ let redirectUrl: string
+
if (res.locals.explicitLogout === true && token.User.pluginAuth && token.authName) {
- PluginManager.Instance.onLogout(token.User.pluginAuth, token.authName, token.User)
+ redirectUrl = await PluginManager.Instance.onLogout(token.User.pluginAuth, token.authName, token.User, this.request)
}
clearCacheByToken(token.accessToken)
token.destroy()
.catch(err => logger.error('Cannot destroy token when revoking token.', { err }))
- return true
+ return { success: true, redirectUrl }
}
- return false
+ return { success: false }
}
async function saveToken (token: TokenInfo, client: OAuthClientModel, user: UserModel) {
+import * as express from 'express'
import { createReadStream, createWriteStream } from 'fs'
import { outputFile, readJSON } from 'fs-extra'
import { basename, join } from 'path'
// ###################### External events ######################
- onLogout (npmName: string, authName: string, user: MUser) {
+ async onLogout (npmName: string, authName: string, user: MUser, req: express.Request) {
const auth = this.getAuth(npmName, authName)
if (auth?.onLogout) {
logger.info('Running onLogout function from auth %s of plugin %s', authName, npmName)
try {
- auth.onLogout(user)
+ // Force await, in case or onLogout returns a promise
+ const result = await auth.onLogout(user, req)
+
+ return typeof result === 'string'
+ ? result
+ : undefined
} catch (err) {
logger.warn('Cannot run onLogout function from auth %s of plugin %s.', authName, npmName, { err })
}
}
+
+ return undefined
}
onSettingsChanged (name: string, settings: any) {
--- /dev/null
+async function register ({
+ registerExternalAuth,
+ peertubeHelpers
+}) {
+ {
+ const result = registerExternalAuth({
+ authName: 'external-auth-7',
+ authDisplayName: () => 'External Auth 7',
+ onAuthRequest: (req, res) => {
+ result.userAuthenticated({
+ req,
+ res,
+ username: 'cid',
+ email: 'cid@example.com',
+ displayName: 'Cid Marquez'
+ })
+ },
+ onLogout: (user, req) => {
+ return 'https://example.com/redirectUrl'
+ }
+ })
+ }
+
+ {
+ const result = registerExternalAuth({
+ authName: 'external-auth-8',
+ authDisplayName: () => 'External Auth 8',
+ onAuthRequest: (req, res) => {
+ result.userAuthenticated({
+ req,
+ res,
+ username: 'cid',
+ email: 'cid@example.com',
+ displayName: 'Cid Marquez'
+ })
+ },
+ onLogout: (user, req) => {
+ return 'https://example.com/redirectUrl?access_token=' + req.headers['authorization'].split(' ')[1]
+ }
+ })
+ }
+}
+
+async function unregister () {
+
+}
+
+module.exports = {
+ register,
+ unregister
+}
+
+// ###########################################################################
--- /dev/null
+{
+ "name": "peertube-plugin-test-external-auth-three",
+ "version": "0.0.1",
+ "description": "External auth three",
+ "engine": {
+ "peertube": ">=1.3.0"
+ },
+ "keywords": [
+ "peertube",
+ "plugin"
+ ],
+ "homepage": "https://github.com/Chocobozzz/PeerTube",
+ "author": "Chocobozzz",
+ "bugs": "https://github.com/Chocobozzz/PeerTube/issues",
+ "library": "./main.js",
+ "staticDirs": {},
+ "css": [],
+ "clientScripts": [],
+ "translations": {}
+}
server = await flushAndRunServer(1)
await setAccessTokensToServers([ server ])
- for (const suffix of [ 'one', 'two' ]) {
+ for (const suffix of [ 'one', 'two', 'three' ]) {
await installPlugin({
url: server.url,
accessToken: server.accessToken,
const config: ServerConfig = res.body
const auths = config.plugin.registeredExternalAuths
- expect(auths).to.have.lengthOf(6)
+ expect(auths).to.have.lengthOf(8)
const auth2 = auths.find((a) => a.authName === 'external-auth-2')
expect(auth2).to.exist
const config: ServerConfig = res.body
const auths = config.plugin.registeredExternalAuths
- expect(auths).to.have.lengthOf(5)
+ expect(auths).to.have.lengthOf(7)
const auth1 = auths.find(a => a.authName === 'external-auth-2')
expect(auth1).to.not.exist
const config: ServerConfig = res.body
const auths = config.plugin.registeredExternalAuths
- expect(auths).to.have.lengthOf(4)
+ expect(auths).to.have.lengthOf(6)
const auth2 = auths.find((a) => a.authName === 'external-auth-2')
expect(auth2).to.not.exist
after(async function () {
await cleanupTests([ server ])
})
+
+ it('Should forward the redirectUrl if the plugin returns one', async function () {
+ const resLogin = await loginExternal({
+ server,
+ npmName: 'test-external-auth-three',
+ authName: 'external-auth-7',
+ username: 'cid'
+ })
+
+ const resLogout = await logout(server.url, resLogin.access_token)
+
+ expect(resLogout.body.redirectUrl).to.equal('https://example.com/redirectUrl')
+ })
+
+ it('Should call the plugin\'s onLogout method with the request', async function () {
+ const resLogin = await loginExternal({
+ server,
+ npmName: 'test-external-auth-three',
+ authName: 'external-auth-8',
+ username: 'cid'
+ })
+
+ const resLogout = await logout(server.url, resLogin.access_token)
+
+ expect(resLogout.body.redirectUrl).to.equal('https://example.com/redirectUrl?access_token=' + resLogin.access_token)
+ })
})
authName: string
// Called by PeerTube when a user from your plugin logged out
- onLogout?(user: MUser): void
+ // Returns a redirectUrl sent to the client or nothing
+ onLogout?(user: MUser, req: express.Request): Promise<string>
// Your plugin can hook PeerTube access/refresh token validity
// So you can control for your plugin the user session lifetime