This commit is contained in:
parent
ec08f8f04e
commit
84be087743
@ -1,5 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 3.2.0
|
||||||
|
|
||||||
|
- Logout function
|
||||||
|
|
||||||
## 3.1.0
|
## 3.1.0
|
||||||
|
|
||||||
- Option to enable body parsing
|
- Option to enable body parsing
|
||||||
|
18
README.md
18
README.md
@ -1,6 +1,6 @@
|
|||||||
# auth-server-helper
|
# auth-server-helper
|
||||||
|
|
||||||
version: 3.1.x
|
version: 3.2.x
|
||||||
|
|
||||||
customizable and simple authentication
|
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
|
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
|
### Exporting and importing public keys to validate tokens across server instances
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -10,6 +10,7 @@ import authority from './Authority';
|
|||||||
import { AuthRequest, AccessSettings } from './AuthHandler';
|
import { AuthRequest, AccessSettings } from './AuthHandler';
|
||||||
import { debug } from './debug';
|
import { debug } from './debug';
|
||||||
import { extract_cookie, CookieSettings } from './cookie';
|
import { extract_cookie, CookieSettings } from './cookie';
|
||||||
|
import blacklist from './Blacklist';
|
||||||
|
|
||||||
const logger = debug ('gateway');
|
const logger = debug ('gateway');
|
||||||
|
|
||||||
@ -181,6 +182,27 @@ class GatewayClass {
|
|||||||
logger ('failed to authenticate, redirecting client');
|
logger ('failed to authenticate, redirecting client');
|
||||||
return this.redirect (res);
|
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 {
|
export default function create_gateway (options: GatewayOptions): Gateway {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@sapphirecode/auth-server-helper",
|
"name": "@sapphirecode/auth-server-helper",
|
||||||
"version": "3.1.0",
|
"version": "3.2.0",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Timo Hocker",
|
"name": "Timo Hocker",
|
||||||
|
@ -16,10 +16,11 @@ export class Response extends http.IncomingMessage {
|
|||||||
export function get (
|
export function get (
|
||||||
// eslint-disable-next-line default-param-last
|
// eslint-disable-next-line default-param-last
|
||||||
headers: http.OutgoingHttpHeaders = {},
|
headers: http.OutgoingHttpHeaders = {},
|
||||||
body?: string
|
body?: string|null,
|
||||||
|
path = ''
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
return new Promise ((resolve) => {
|
return new Promise ((resolve) => {
|
||||||
const req = http.request ('http://localhost:3000', {
|
const req = http.request (`http://localhost:3000${path}`, {
|
||||||
headers,
|
headers,
|
||||||
method: typeof body === 'string' ? 'POST' : 'GET'
|
method: typeof body === 'string' ? 'POST' : 'GET'
|
||||||
}, (res: Response) => {
|
}, (res: Response) => {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import { create_gateway } from '../../lib/index';
|
import { GatewayClass, create_gateway } from '../../lib/index';
|
||||||
import authority from '../../lib/Authority';
|
import authority from '../../lib/Authority';
|
||||||
import blacklist from '../../lib/Blacklist';
|
import blacklist from '../../lib/Blacklist';
|
||||||
import { clock_finalize, clock_setup, get } from '../Helper';
|
import { clock_finalize, clock_setup, get } from '../Helper';
|
||||||
@ -18,7 +18,7 @@ describe ('gateway', () => {
|
|||||||
beforeAll (() => {
|
beforeAll (() => {
|
||||||
clock_setup ();
|
clock_setup ();
|
||||||
|
|
||||||
const g = create_gateway ({
|
const g = new GatewayClass ({
|
||||||
redirect_url: 'http://localhost/auth',
|
redirect_url: 'http://localhost/auth',
|
||||||
cookie: { name: 'cookie_jar' },
|
cookie: { name: 'cookie_jar' },
|
||||||
refresh_cookie: { name: 'mint_cookies' },
|
refresh_cookie: { name: 'mint_cookies' },
|
||||||
@ -31,11 +31,15 @@ describe ('gateway', () => {
|
|||||||
|
|
||||||
server = http.createServer ((req, res) => {
|
server = http.createServer ((req, res) => {
|
||||||
const passed_handler = () => {
|
const passed_handler = () => {
|
||||||
|
if (typeof req.url !== 'undefined') {
|
||||||
|
if (req.url.endsWith ('logout'))
|
||||||
|
g.logout (req);
|
||||||
|
}
|
||||||
res.writeHead (200);
|
res.writeHead (200);
|
||||||
const con = req.connection as unknown as Record<string, unknown>;
|
const con = req.connection as unknown as Record<string, unknown>;
|
||||||
res.end (JSON.stringify (con.auth));
|
res.end (JSON.stringify (con.auth));
|
||||||
};
|
};
|
||||||
g (req, res, passed_handler);
|
g.process_request (req, res, passed_handler);
|
||||||
});
|
});
|
||||||
server.listen (3000);
|
server.listen (3000);
|
||||||
});
|
});
|
||||||
@ -169,4 +173,23 @@ describe ('gateway', () => {
|
|||||||
})
|
})
|
||||||
.toThrowError ('access and refresh cookies cannot have the same name');
|
.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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user