automatic refresh tokens
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			This commit is contained in:
		@@ -1,5 +1,10 @@
 | 
			
		||||
# Changelog
 | 
			
		||||
 | 
			
		||||
## 2.2.0
 | 
			
		||||
 | 
			
		||||
- Allow refresh tokens to be sent on a separate cookie
 | 
			
		||||
- Automatic token refresh if the access token is expired and the cookie header contains a valid refresh token
 | 
			
		||||
 | 
			
		||||
## 2.1.0
 | 
			
		||||
 | 
			
		||||
- Allow access to Gateway functions like authenticate, get_cookie_auth, get_header_auth, redirect, deny
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.md
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
# auth-server-helper
 | 
			
		||||
 | 
			
		||||
version: 2.1.x
 | 
			
		||||
version: 2.2.x
 | 
			
		||||
 | 
			
		||||
customizable and simple authentication
 | 
			
		||||
 | 
			
		||||
@@ -23,7 +23,12 @@ const {create_gateway} = require('@sapphirecode/auth-server-helper');
 | 
			
		||||
 | 
			
		||||
const gateway = create_gateway({
 | 
			
		||||
  redirect_url: '/auth', // if defined, unauthorized requests will be redirected
 | 
			
		||||
  cookie_name: 'auth_cookie', // if defined, access tokens will be read from this cookie
 | 
			
		||||
  cookie_name: 'auth_cookie', // if defined, access tokens will be read from this cookie,
 | 
			
		||||
  refresh_cookie_name: 'refresh_cookie', // if defined, refresh tokens will be read and used to automatically refresh client tokens (requires the refresh_settings attribute)
 | 
			
		||||
  refresh_settings: {
 | 
			
		||||
    // same as settings for allow_access under section 2
 | 
			
		||||
    // the options redirect_to and leave_open are not supported here
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// express
 | 
			
		||||
@@ -98,7 +103,8 @@ const handler = create_auth_handler(
 | 
			
		||||
        // the same works in handlers after the gateway, information is always stored in request.connection.auth
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    cookie_name: 'auth_cookie', // if defined, access tokens will be stored in this cookie
 | 
			
		||||
    cookie_name: 'auth_cookie', // if defined, access tokens will be stored in this cookie,
 | 
			
		||||
    refresh_cookie_name: 'refresh_cookie' // if defined, refresh tokens will be stored in this cookie
 | 
			
		||||
  }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,9 @@ interface AccessResponse {
 | 
			
		||||
  refresh_expires_in?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AuthHandler =
 | 
			
		||||
  (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
 | 
			
		||||
 | 
			
		||||
class AuthRequest {
 | 
			
		||||
  public request: IncomingMessage;
 | 
			
		||||
  public response: ServerResponse;
 | 
			
		||||
@@ -47,6 +50,7 @@ class AuthRequest {
 | 
			
		||||
  public body: string;
 | 
			
		||||
 | 
			
		||||
  private _cookie_name?: string;
 | 
			
		||||
  private _refresh_cookie_name?: string;
 | 
			
		||||
  private _is_successful: boolean;
 | 
			
		||||
 | 
			
		||||
  public get is_successful (): boolean {
 | 
			
		||||
@@ -57,7 +61,8 @@ class AuthRequest {
 | 
			
		||||
    req: IncomingMessage,
 | 
			
		||||
    res: ServerResponse,
 | 
			
		||||
    body: string,
 | 
			
		||||
    cookie?: string
 | 
			
		||||
    cookie?: string,
 | 
			
		||||
    refresh_cookie?: string
 | 
			
		||||
  ) {
 | 
			
		||||
    this.request = req;
 | 
			
		||||
    this.response = res;
 | 
			
		||||
@@ -67,6 +72,7 @@ class AuthRequest {
 | 
			
		||||
    this.user = '';
 | 
			
		||||
    this.password = '';
 | 
			
		||||
    this._cookie_name = cookie;
 | 
			
		||||
    this._refresh_cookie_name = refresh_cookie;
 | 
			
		||||
    this._is_successful = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -102,12 +108,10 @@ class AuthRequest {
 | 
			
		||||
      expires_in:   access_token_expires_in
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (typeof this._cookie_name === 'string') {
 | 
			
		||||
      this.response.setHeader (
 | 
			
		||||
        'Set-Cookie',
 | 
			
		||||
        `${this._cookie_name}=${at.signature}`
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    const cookies = [];
 | 
			
		||||
 | 
			
		||||
    if (typeof this._cookie_name === 'string')
 | 
			
		||||
      cookies.push (`${this._cookie_name}=${at.signature}`);
 | 
			
		||||
 | 
			
		||||
    if (include_refresh_token) {
 | 
			
		||||
      if (typeof refresh_token_expires_in !== 'number')
 | 
			
		||||
@@ -120,6 +124,16 @@ class AuthRequest {
 | 
			
		||||
      res.refresh_token = rt.signature;
 | 
			
		||||
      res.refresh_expires_in = refresh_token_expires_in;
 | 
			
		||||
      result.refresh_token_id = rt.id;
 | 
			
		||||
 | 
			
		||||
      if (typeof this._refresh_cookie_name === 'string')
 | 
			
		||||
        cookies.push (`${this._refresh_cookie_name}=${rt.signature}`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (cookies.length > 0) {
 | 
			
		||||
      this.response.setHeader (
 | 
			
		||||
        'Set-Cookie',
 | 
			
		||||
        cookies
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._is_successful = true;
 | 
			
		||||
@@ -194,6 +208,7 @@ interface CreateHandlerOptions {
 | 
			
		||||
  refresh?: AccessSettings;
 | 
			
		||||
  modules?: Record<string, AuthRequestHandler>;
 | 
			
		||||
  cookie_name?: string;
 | 
			
		||||
  refresh_cookie_name?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line max-lines-per-function
 | 
			
		||||
@@ -261,7 +276,13 @@ function process_request (
 | 
			
		||||
export default function create_auth_handler (
 | 
			
		||||
  default_handler: AuthRequestHandler,
 | 
			
		||||
  options?: CreateHandlerOptions
 | 
			
		||||
) {
 | 
			
		||||
): AuthHandler {
 | 
			
		||||
  if (
 | 
			
		||||
    typeof options?.cookie_name !== 'undefined'
 | 
			
		||||
    && options.cookie_name === options.refresh_cookie_name
 | 
			
		||||
  )
 | 
			
		||||
    throw new Error ('access and refresh cookies cannot have the same name');
 | 
			
		||||
 | 
			
		||||
  return async (
 | 
			
		||||
    req: IncomingMessage,
 | 
			
		||||
    res: ServerResponse
 | 
			
		||||
@@ -276,7 +297,13 @@ export default function create_auth_handler (
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const request = new AuthRequest (req, res, body, options?.cookie_name);
 | 
			
		||||
    const request = new AuthRequest (
 | 
			
		||||
      req,
 | 
			
		||||
      res,
 | 
			
		||||
      body,
 | 
			
		||||
      options?.cookie_name,
 | 
			
		||||
      options?.refresh_cookie_name
 | 
			
		||||
    );
 | 
			
		||||
    const token = (/(?<type>\S+) (?<token>.+)/ui)
 | 
			
		||||
      .exec (req.headers.authorization as string);
 | 
			
		||||
 | 
			
		||||
@@ -292,5 +319,6 @@ export {
 | 
			
		||||
  AccessResponse,
 | 
			
		||||
  AuthRequest,
 | 
			
		||||
  AuthRequestHandler,
 | 
			
		||||
  CreateHandlerOptions
 | 
			
		||||
  CreateHandlerOptions,
 | 
			
		||||
  AuthHandler
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
import { IncomingMessage, ServerResponse } from 'http';
 | 
			
		||||
import { run_regex } from '@sapphirecode/utilities';
 | 
			
		||||
import authority from './Authority';
 | 
			
		||||
import { AuthRequest, AccessSettings } from './AuthHandler';
 | 
			
		||||
 | 
			
		||||
type AnyFunc = (...args: unknown[]) => unknown;
 | 
			
		||||
type Gateway = (
 | 
			
		||||
@@ -15,15 +16,33 @@ type Gateway = (
 | 
			
		||||
  res: ServerResponse, next: AnyFunc
 | 
			
		||||
) => unknown;
 | 
			
		||||
 | 
			
		||||
interface RefreshSettings extends AccessSettings {
 | 
			
		||||
  leave_open?: never;
 | 
			
		||||
  redirect_to?: never;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface GatewayOptions {
 | 
			
		||||
  redirect_url?: string;
 | 
			
		||||
  cookie_name?: string;
 | 
			
		||||
  refresh_cookie_name?: string;
 | 
			
		||||
  refresh_settings?: RefreshSettings;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface AuthCookies {
 | 
			
		||||
  access_cookie: string | null;
 | 
			
		||||
  refresh_cookie: string | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class GatewayClass {
 | 
			
		||||
  private _options: GatewayOptions;
 | 
			
		||||
 | 
			
		||||
  public constructor (options: GatewayOptions = {}) {
 | 
			
		||||
    if (
 | 
			
		||||
      typeof options.cookie_name === 'string'
 | 
			
		||||
      && options.cookie_name === options.refresh_cookie_name
 | 
			
		||||
    )
 | 
			
		||||
      throw new Error ('access and refresh cookies cannot have the same name');
 | 
			
		||||
 | 
			
		||||
    this._options = options;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -52,25 +71,33 @@ class GatewayClass {
 | 
			
		||||
    return auth.groups?.data;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public get_cookie_auth (req: IncomingMessage): string | null {
 | 
			
		||||
    if (typeof this._options.cookie_name === 'undefined')
 | 
			
		||||
      return null;
 | 
			
		||||
    let auth = null;
 | 
			
		||||
  public get_cookie_auth (req: IncomingMessage): AuthCookies {
 | 
			
		||||
    const result: AuthCookies = {
 | 
			
		||||
      access_cookie:  null,
 | 
			
		||||
      refresh_cookie: null
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const cookie_regex = /(?:^|;)\s*(?<name>[^;=]+)=(?<value>[^;]+)/gu;
 | 
			
		||||
 | 
			
		||||
    run_regex (
 | 
			
		||||
      /(?:^|;)\s*(?<name>[^;=]+)=(?<value>[^;]+)/gu,
 | 
			
		||||
      cookie_regex,
 | 
			
		||||
      req.headers.cookie,
 | 
			
		||||
      (res: RegExpMatchArray) => {
 | 
			
		||||
        if (res.groups?.name === this._options.cookie_name)
 | 
			
		||||
          auth = res.groups?.value;
 | 
			
		||||
          result.access_cookie = res.groups?.value as string;
 | 
			
		||||
        else if (res.groups?.name === this._options.refresh_cookie_name)
 | 
			
		||||
          result.refresh_cookie = res.groups?.value as string;
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
    return auth;
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public authenticate (req: IncomingMessage): boolean {
 | 
			
		||||
    const cookies = this.get_cookie_auth (req);
 | 
			
		||||
    let auth = this.get_header_auth (req);
 | 
			
		||||
    if (auth === null)
 | 
			
		||||
      auth = this.get_cookie_auth (req);
 | 
			
		||||
      auth = cookies.access_cookie;
 | 
			
		||||
    if (auth === null)
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
@@ -82,13 +109,55 @@ class GatewayClass {
 | 
			
		||||
    return ver.authorized;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public process_request (
 | 
			
		||||
  public async try_refresh (
 | 
			
		||||
    req: IncomingMessage,
 | 
			
		||||
    res: ServerResponse
 | 
			
		||||
  ): Promise<boolean> {
 | 
			
		||||
    if (
 | 
			
		||||
      typeof this._options.refresh_cookie_name === 'undefined'
 | 
			
		||||
      || typeof this._options.refresh_settings === 'undefined'
 | 
			
		||||
    )
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    const refresh = this.get_cookie_auth (req).refresh_cookie;
 | 
			
		||||
    if (refresh === null)
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    const ver = authority.verify (refresh);
 | 
			
		||||
    if (ver.type === 'refresh_token' && ver.valid) {
 | 
			
		||||
      const auth_request = new AuthRequest (
 | 
			
		||||
        req,
 | 
			
		||||
        res,
 | 
			
		||||
        ''
 | 
			
		||||
        , this._options.cookie_name,
 | 
			
		||||
        this._options.refresh_cookie_name
 | 
			
		||||
      );
 | 
			
		||||
      const refresh_result = await auth_request.allow_access ({
 | 
			
		||||
        ...this._options.refresh_settings,
 | 
			
		||||
        leave_open: true
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const con = req.connection as unknown as Record<string, unknown>;
 | 
			
		||||
      con.auth = {
 | 
			
		||||
        token_id:   refresh_result.access_token_id,
 | 
			
		||||
        token_data: this._options.refresh_settings.data
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async process_request (
 | 
			
		||||
    req: IncomingMessage,
 | 
			
		||||
    res: ServerResponse,
 | 
			
		||||
    next: AnyFunc
 | 
			
		||||
  ): unknown {
 | 
			
		||||
  ): Promise<unknown> {
 | 
			
		||||
    if (this.authenticate (req))
 | 
			
		||||
      return next ();
 | 
			
		||||
    if (await this.try_refresh (req, res))
 | 
			
		||||
      return next ();
 | 
			
		||||
    return this.redirect (res);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,8 @@ import create_auth_handler, {
 | 
			
		||||
  AuthRequestHandler,
 | 
			
		||||
  AuthRequest,
 | 
			
		||||
  AccessSettings,
 | 
			
		||||
  AccessResult
 | 
			
		||||
  AccessResult,
 | 
			
		||||
  AuthHandler
 | 
			
		||||
} from './AuthHandler';
 | 
			
		||||
import authority, {
 | 
			
		||||
  VerificationResult,
 | 
			
		||||
@@ -44,6 +45,7 @@ export {
 | 
			
		||||
  CreateHandlerOptions,
 | 
			
		||||
  AuthRequestHandler,
 | 
			
		||||
  AuthRequest,
 | 
			
		||||
  AuthHandler,
 | 
			
		||||
  AccessSettings,
 | 
			
		||||
  AccessResult,
 | 
			
		||||
  VerificationResult,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@sapphirecode/auth-server-helper",
 | 
			
		||||
  "version": "2.1.4",
 | 
			
		||||
  "version": "2.2.0",
 | 
			
		||||
  "main": "dist/index.js",
 | 
			
		||||
  "author": {
 | 
			
		||||
    "name": "Timo Hocker",
 | 
			
		||||
 
 | 
			
		||||
@@ -110,8 +110,9 @@ describe ('auth handler', () => {
 | 
			
		||||
        req.deny ();
 | 
			
		||||
      }
 | 
			
		||||
    }, {
 | 
			
		||||
      cookie_name: 'cookie_jar',
 | 
			
		||||
      refresh:     {
 | 
			
		||||
      cookie_name:         'cookie_jar',
 | 
			
		||||
      refresh_cookie_name: 'mint_cookies',
 | 
			
		||||
      refresh:             {
 | 
			
		||||
        access_token_expires_in:  expires_seconds,
 | 
			
		||||
        refresh_token_expires_in: refresh_expires_seconds,
 | 
			
		||||
        include_refresh_token:    true
 | 
			
		||||
@@ -158,6 +159,8 @@ describe ('auth handler', () => {
 | 
			
		||||
      .toEqual ('bearer');
 | 
			
		||||
    expect (resp1.headers['set-cookie'])
 | 
			
		||||
      .toContain (`cookie_jar=${res1.at}`);
 | 
			
		||||
    expect (resp1.headers['set-cookie'])
 | 
			
		||||
      .toContain (`mint_cookies=${res1.rt}`);
 | 
			
		||||
 | 
			
		||||
    check_token (res1.at as string, 'access_token');
 | 
			
		||||
    expect (res1.data.expires_in)
 | 
			
		||||
@@ -177,6 +180,8 @@ describe ('auth handler', () => {
 | 
			
		||||
      .toEqual ('bearer');
 | 
			
		||||
    expect (resp2.headers['set-cookie'])
 | 
			
		||||
      .toContain (`cookie_jar=${res2.at}`);
 | 
			
		||||
    expect (resp2.headers['set-cookie'])
 | 
			
		||||
      .toContain (`mint_cookies=${res2.rt}`);
 | 
			
		||||
 | 
			
		||||
    check_token (res2.at as string, 'access_token');
 | 
			
		||||
    expect (res2.data.expires_in)
 | 
			
		||||
@@ -207,6 +212,8 @@ describe ('auth handler', () => {
 | 
			
		||||
      .toEqual ('bearer');
 | 
			
		||||
    expect (resp1.headers['set-cookie'])
 | 
			
		||||
      .toContain (`cookie_jar=${res1.at}`);
 | 
			
		||||
    expect (resp1.headers['set-cookie'])
 | 
			
		||||
      .toContain (`mint_cookies=${res1.rt}`);
 | 
			
		||||
 | 
			
		||||
    check_token (res1.at as string, 'access_token');
 | 
			
		||||
    expect (res1.data.expires_in)
 | 
			
		||||
@@ -230,6 +237,8 @@ describe ('auth handler', () => {
 | 
			
		||||
      .toEqual ('bearer');
 | 
			
		||||
    expect (resp1.headers['set-cookie'])
 | 
			
		||||
      .toContain (`cookie_jar=${res1.at}`);
 | 
			
		||||
    expect (resp1.headers['set-cookie'])
 | 
			
		||||
      .toContain (`mint_cookies=${res1.rt}`);
 | 
			
		||||
 | 
			
		||||
    check_token (res1.at as string, 'access_token');
 | 
			
		||||
    expect (res1.data.expires_in)
 | 
			
		||||
@@ -301,6 +310,8 @@ describe ('auth handler', () => {
 | 
			
		||||
      .toEqual ('bearer');
 | 
			
		||||
    expect (resp2.headers['set-cookie'])
 | 
			
		||||
      .toContain (`cookie_jar=${res2.at}`);
 | 
			
		||||
    expect (resp2.headers['set-cookie'])
 | 
			
		||||
      .toContain (`mint_cookies=${res2.rt}`);
 | 
			
		||||
 | 
			
		||||
    check_token (res2.at as string, 'access_token');
 | 
			
		||||
    expect (res2.data.expires_in)
 | 
			
		||||
@@ -354,4 +365,14 @@ describe ('auth handler', () => {
 | 
			
		||||
    expect (signature).not.toEqual ('');
 | 
			
		||||
    check_token (signature, 'access_token');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it ('should disallow access and refresh cookies with the same name', () => {
 | 
			
		||||
    expect (() => {
 | 
			
		||||
      create_auth_handler (() => Promise.resolve (), {
 | 
			
		||||
        cookie_name:         'foo',
 | 
			
		||||
        refresh_cookie_name: 'foo'
 | 
			
		||||
      });
 | 
			
		||||
    })
 | 
			
		||||
      .toThrowError ('access and refresh cookies cannot have the same name');
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,14 @@ describe ('gateway', () => {
 | 
			
		||||
    clock_setup ();
 | 
			
		||||
 | 
			
		||||
    const g = create_gateway ({
 | 
			
		||||
      redirect_url: 'http://localhost/auth',
 | 
			
		||||
      cookie_name:  'cookie_jar'
 | 
			
		||||
      redirect_url:        'http://localhost/auth',
 | 
			
		||||
      cookie_name:         'cookie_jar',
 | 
			
		||||
      refresh_cookie_name: 'mint_cookies',
 | 
			
		||||
      refresh_settings:    {
 | 
			
		||||
        access_token_expires_in:  600,
 | 
			
		||||
        include_refresh_token:    true,
 | 
			
		||||
        refresh_token_expires_in: 3600
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    server = http.createServer ((req, res) => {
 | 
			
		||||
@@ -70,6 +76,22 @@ describe ('gateway', () => {
 | 
			
		||||
      .toEqual (token.id);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it ('should automatically return new tokens', async () => {
 | 
			
		||||
    const token = await authority.sign ('access_token', 60);
 | 
			
		||||
    const refresh = await authority.sign ('refresh_token', 3600);
 | 
			
		||||
    jasmine.clock ()
 | 
			
		||||
      .tick (70000);
 | 
			
		||||
    const resp = await get (
 | 
			
		||||
      // eslint-disable-next-line max-len
 | 
			
		||||
      { cookie: `foo=bar;cookie_jar=${token.signature};asd=efg;mint_cookies=${refresh.signature}` }
 | 
			
		||||
    );
 | 
			
		||||
    expect (resp.statusCode)
 | 
			
		||||
      .toEqual (200);
 | 
			
		||||
    expect (JSON.parse (resp.body as string).token_id)
 | 
			
		||||
      .not
 | 
			
		||||
      .toEqual (token.id);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it ('should correctly deliver token data', async () => {
 | 
			
		||||
    const token = await authority.sign ('access_token', 60, { data: 'foobar' });
 | 
			
		||||
    const resp = await get ({ authorization: `Bearer ${token.signature}` });
 | 
			
		||||
@@ -137,4 +159,11 @@ describe ('gateway', () => {
 | 
			
		||||
    expect (resp.headers.location)
 | 
			
		||||
      .toEqual ('http://localhost/auth');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it ('should disallow access and refresh cookies with the same name', () => {
 | 
			
		||||
    expect (() => {
 | 
			
		||||
      create_gateway ({ cookie_name: 'foo', refresh_cookie_name: 'foo' });
 | 
			
		||||
    })
 | 
			
		||||
      .toThrowError ('access and refresh cookies cannot have the same name');
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user