diff --git a/.golangci.yaml b/.golangci.yaml
new file mode 100644
index 0000000..843af8b
--- /dev/null
+++ b/.golangci.yaml
@@ -0,0 +1,19 @@
+run:
+  deadline: 5m
+linters:
+  enable-all: true
+  disable:
+    - gochecknoglobals
+    - goimports
+    - gocritic
+linters-settings:
+  lll:
+    line-length: 420
+  gocyclo:
+    min-complexity: 40
+
+issues:
+  exclude-rules:
+    - path: "exported.go"
+      linters:
+        - dupl
diff --git a/main.go b/cmd/massdl.go
similarity index 74%
rename from main.go
rename to cmd/massdl.go
index 3545d1c..97f4bb0 100644
--- a/main.go
+++ b/cmd/massdl.go
@@ -5,6 +5,7 @@
 package main
 
 import (
+	"gitlab.com/fat0troll/uploader_tools/domains/loginer/v1"
 	"gitlab.com/fat0troll/uploader_tools/internal/context"
 )
 
@@ -13,4 +14,10 @@ func main() {
 	c.Init()
 	c.Logger.Info().Msg("NNM-Club mass torrent files downloader is starting")
 	c.InitConfig()
+
+	loginerv1.New(c)
+
+	c.Flagger.Parse()
+
+	loginerv1.Process()
 }
diff --git a/domains/loginer/v1/checks.go b/domains/loginer/v1/checks.go
new file mode 100644
index 0000000..f216762
--- /dev/null
+++ b/domains/loginer/v1/checks.go
@@ -0,0 +1,12 @@
+// NNM-Club torrent filess mass downloader
+// Created for Uploaders group
+// Copyright (c) 2012-2019 Vladimir "fat0troll" Hodakov
+
+package loginerv1
+
+// checkConfig checks if there's some errors in config file
+func checkConfig() {
+	if c.Config.URL == "" || c.Config.Password == "" || c.Config.Username == "" {
+		dlog.Fatal().Msg("Конфиг не заполнен или заполнен не до конца. Запустите программу с ключом -auth для авторизации.")
+	}
+}
diff --git a/domains/loginer/v1/exported.go b/domains/loginer/v1/exported.go
new file mode 100644
index 0000000..c12cd5d
--- /dev/null
+++ b/domains/loginer/v1/exported.go
@@ -0,0 +1,43 @@
+// NNM-Club torrent filess mass downloader
+// Created for Uploaders group
+// Copyright (c) 2012-2019 Vladimir "fat0troll" Hodakov
+
+package loginerv1
+
+import (
+	"github.com/rs/zerolog"
+	"gitlab.com/fat0troll/uploader_tools/internal/context"
+	"gitlab.com/pztrn/flagger"
+)
+
+var (
+	c    *context.Context
+	dlog zerolog.Logger
+)
+
+// New initializes package
+func New(cc *context.Context) {
+	c = cc
+	dlog = c.Logger.With().Str("domain", "loginer").Int("version", 1).Logger()
+
+	_ = c.Flagger.AddFlag(&flagger.Flag{
+		Name:         "auth",
+		Description:  "Start authentication to NNM-Club website and create application config.",
+		Type:         "bool",
+		DefaultValue: false,
+	})
+
+	dlog.Info().Msg("Domain initialized")
+}
+
+// Process handles authorization
+func Process() {
+	auth, _ := c.Flagger.GetBoolValue("auth")
+
+	if auth {
+		login()
+	}
+
+	checkConfig()
+	obtainCookies()
+}
diff --git a/domains/loginer/v1/login.go b/domains/loginer/v1/login.go
new file mode 100644
index 0000000..77d9528
--- /dev/null
+++ b/domains/loginer/v1/login.go
@@ -0,0 +1,90 @@
+// NNM-Club torrent filess mass downloader
+// Created for Uploaders group
+// Copyright (c) 2012-2019 Vladimir "fat0troll" Hodakov
+
+package loginerv1
+
+import (
+	"bufio"
+	"net/http"
+	"net/url"
+	"os"
+	"strings"
+)
+
+// login function name is self-descriptive.
+// After successful login it will write cookie file and config in system's
+// config directory
+func login() {
+	dlog.Info().Msg("Введите адрес сайта NNM-Club, без протокола (к примеру, nnmclub.ro)")
+	// First enter is site name, second and third are user credentials
+	scanner := bufio.NewScanner(os.Stdin)
+	scanline := 0
+	for scanner.Scan() {
+		scanline++
+		switch {
+		case scanline == 1:
+			c.Config.URL = scanner.Text()
+			dlog.Info().Msg("Введите имя пользователя")
+		case scanline == 2:
+			c.Config.Username = scanner.Text()
+			dlog.Info().Msg("Введите пароль")
+		default:
+			c.Config.Password = scanner.Text()
+		}
+		if scanline == 3 {
+			break
+		}
+	}
+	if scanner.Err() != nil {
+		dlog.Fatal().Err(scanner.Err()).Msg("Не удалось прочитать пользовательский ввод.")
+	}
+
+	c.SaveConfig()
+
+	obtainCookies()
+
+	dlog.Info().Msg("Логин прошёл успешно. Перезапустите программу с ключём -forum НОМЕР_ФОРУМА.")
+	os.Exit(0)
+}
+
+// obtainCookie tries to login to NNM-Club and saves resulting cookie
+// If it can't save cookie, the program will terminate with error and you will
+// need to authorize again or retry cookie obtaining.
+func obtainCookies() {
+	// This value is obtained from login.php sources.
+	nnmClubCode := "58161005a04f0ee5"
+
+	client := http.Client{
+		// This is disables redirects for this request. Otherwise we can't obtain cookies
+		CheckRedirect: func(req *http.Request, via []*http.Request) error {
+			return http.ErrUseLastResponse
+		},
+	}
+
+	formData := url.Values{}
+	formData.Add("username", c.Config.Username)
+	formData.Add("password", c.Config.Password)
+	formData.Add("autologin", "on")
+	formData.Add("redirect", "index.php")
+	formData.Add("code", nnmClubCode)
+	formData.Add("login", "%C2%F5%EE%E4")
+
+	url := "https://" + c.Config.URL + "/forum/login.php"
+	req, _ := http.NewRequest(http.MethodPost, url, strings.NewReader(formData.Encode()))
+	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
+
+	resp, err := client.Do(req)
+	if err != nil {
+		dlog.Fatal().Err(err).Msg("Не удалось отправить запрос на авторизацию в NNM-Club.")
+	}
+	defer resp.Body.Close()
+
+	if len(resp.Cookies()) == 0 {
+		dlog.Fatal().Msg("Не удалось получить печеньки от сайта NNM-Club. Неправильные имя/пароль или адрес сайта.")
+	}
+
+	c.SetCookies(resp.Cookies())
+
+	dlog.Info().Str("username", c.Config.Username).Msg("Успешный логин.")
+}
diff --git a/internal/context/context.go b/internal/context/context.go
index b9cb9ba..fb79a02 100644
--- a/internal/context/context.go
+++ b/internal/context/context.go
@@ -11,6 +11,7 @@ import (
 	"github.com/rs/zerolog"
 	"gitlab.com/pztrn/flagger"
 	"log"
+	"net/http"
 	"os"
 	"path/filepath"
 	"runtime"
@@ -95,3 +96,7 @@ func (c *Context) SaveConfig() {
 		dlog.Fatal().Err(err).Msg("Failed to encode config")
 	}
 }
+
+func (c *Context) SetCookies(cookies []*http.Cookie) {
+	c.Cookies = append(c.Cookies, cookies...)
+}
diff --git a/internal/context/exported.go b/internal/context/exported.go
index f6c2fc6..d1f8a9e 100644
--- a/internal/context/exported.go
+++ b/internal/context/exported.go
@@ -8,6 +8,7 @@ import (
 	"github.com/rs/zerolog"
 	"gitlab.com/fat0troll/uploader_tools/internal/config"
 	"gitlab.com/pztrn/flagger"
+	"net/http"
 )
 
 var (
@@ -21,6 +22,7 @@ type Context struct {
 	Config  config.Config
 	Flagger *flagger.Flagger
 	Logger  zerolog.Logger
+	Cookies []*http.Cookie
 }
 
 // New creates new Context