logout function
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Timo Hocker 2022-05-02 13:30:09 +02:00
parent ec08f8f04e
commit 84be087743
No known key found for this signature in database
GPG Key ID: 3B86485AC71C835C
6 changed files with 73 additions and 7 deletions

View File

@ -1,5 +1,9 @@
# Changelog
## 3.2.0
- Logout function
## 3.1.0
- Option to enable body parsing

View File

@ -1,6 +1,6 @@
# auth-server-helper
version: 3.1.x
version: 3.2.x
customizable and simple authentication
@ -168,6 +168,22 @@ const {blacklist} = require('@sapphirecode/auth-server-helper');
blacklist.add_signature(token_id); // the token id is returned from any function that creates tokens
```
#### Logout function
```js
const {logout} = require('@sapphirecode/auth-server-helper');
// create a new express route
app.get('logout',(req,res)=>{
// call the gateway's logout function
gateway.logout(req);
// respond ok
res.status(200);
res.end();
})
```
### Exporting and importing public keys to validate tokens across server instances
```js

View File

@ -10,6 +10,7 @@ import authority from './Authority';
import { AuthRequest, AccessSettings } from './AuthHandler';
import { debug } from './debug';
import { extract_cookie, CookieSettings } from './cookie';
import blacklist from './Blacklist';
const logger = debug ('gateway');
@ -181,6 +182,27 @@ class GatewayClass {
logger ('failed to authenticate, redirecting client');
return this.redirect (res);
}
public logout (req: IncomingMessage): void {
const l = logger.extend ('logout');
l ('invalidating all submitted tokens');
const auth_strings = [
this.get_header_auth (req),
extract_cookie (this._options.cookie?.name, req.headers.cookie),
extract_cookie (this._options.refresh_cookie?.name, req.headers.cookie)
];
const tokens = auth_strings
.filter ((v) => v !== null)
.map ((v) => authority.verify (v as string))
.filter ((v) => v.valid);
l ('found %d tokens: %O', tokens.length, tokens);
for (const token of tokens)
blacklist.add_signature (token.id);
l ('complete');
}
}
export default function create_gateway (options: GatewayOptions): Gateway {

View File

@ -1,6 +1,6 @@
{
"name": "@sapphirecode/auth-server-helper",
"version": "3.1.0",
"version": "3.2.0",
"main": "dist/index.js",
"author": {
"name": "Timo Hocker",

View File

@ -16,10 +16,11 @@ export class Response extends http.IncomingMessage {
export function get (
// eslint-disable-next-line default-param-last
headers: http.OutgoingHttpHeaders = {},
body?: string
body?: string|null,
path = ''
): Promise<Response> {
return new Promise ((resolve) => {
const req = http.request ('http://localhost:3000', {
const req = http.request (`http://localhost:3000${path}`, {
headers,
method: typeof body === 'string' ? 'POST' : 'GET'
}, (res: Response) => {

View File

@ -6,7 +6,7 @@
*/
import http from 'http';
import { create_gateway } from '../../lib/index';
import { GatewayClass, create_gateway } from '../../lib/index';
import authority from '../../lib/Authority';
import blacklist from '../../lib/Blacklist';
import { clock_finalize, clock_setup, get } from '../Helper';
@ -18,7 +18,7 @@ describe ('gateway', () => {
beforeAll (() => {
clock_setup ();
const g = create_gateway ({
const g = new GatewayClass ({
redirect_url: 'http://localhost/auth',
cookie: { name: 'cookie_jar' },
refresh_cookie: { name: 'mint_cookies' },
@ -31,11 +31,15 @@ describe ('gateway', () => {
server = http.createServer ((req, res) => {
const passed_handler = () => {
if (typeof req.url !== 'undefined') {
if (req.url.endsWith ('logout'))
g.logout (req);
}
res.writeHead (200);
const con = req.connection as unknown as Record<string, unknown>;
res.end (JSON.stringify (con.auth));
};
g (req, res, passed_handler);
g.process_request (req, res, passed_handler);
});
server.listen (3000);
});
@ -169,4 +173,23 @@ describe ('gateway', () => {
})
.toThrowError ('access and refresh cookies cannot have the same name');
});
it ('should logout all tokens', async () => {
const token = await authority.sign ('access_token', 60);
const refresh = await authority.sign ('refresh_token', 3600);
const resp = await get (
// eslint-disable-next-line max-len
{ cookie: `foo=bar;cookie_jar=${token.signature};asd=efg;mint_cookies=${refresh.signature}` },
null,
'/logout'
);
expect (resp.statusCode)
.toEqual (200);
const blacklisted = blacklist.export_blacklist ()
.map ((v) => v.hash);
expect (blacklisted)
.toContain (token.id);
expect (blacklisted)
.toContain (refresh.id);
});
});