.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "Auth::GoogleAuth 3pm" .TH Auth::GoogleAuth 3pm "2021-01-12" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Auth::GoogleAuth \- Google Authenticator TBOT Abstraction .SH "VERSION" .IX Header "VERSION" version 1.03 .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& use Auth::GoogleAuth; \& \& my $auth = Auth::GoogleAuth\->new; \& \& $auth = Auth::GoogleAuth\->new({ \& secret => \*(Aqsome secret string thing\*(Aq, \& issuer => \*(AqGryphon Shafer\*(Aq, \& key_id => \*(Aqgryphon@cpan.org\*(Aq, \& }); \& \& $auth\->secret(); # get/set \& $auth\->secret32(); # get/set \& $auth\->issuer(); # get/set \& $auth\->key_id(); # get/set \& \& my $secret32 = $auth\->generate_secret32; \& \& $auth\->clear; \& \& my $url_0 = $auth\->qr_code; \& my $url_1 = $auth\->qr_code( \& \*(Aqbv5o3disbutz4tl3\*(Aq, # secret32 \& \*(Aqgryphon@cpan.org\*(Aq, # key_id \& \*(AqGryphon Shafer\*(Aq, # issuer \& ); \& my $url_2 = $auth\->qr_code( \& \*(Aqbv5o3disbutz4tl3\*(Aq, \*(Aqgryphon@cpan.org\*(Aq, \*(AqGryphon Shafer\*(Aq, 1, \& ); \& \& my $otpauth = $auth\->otpauth; \& \& my $code_0 = $auth\->code; \& my $code_1 = $auth\->code( \*(Aqutz4tl3bv5o3disb\*(Aq, 1438643789, 30 ); \& \& my $verification_0 = $auth\->verify(\*(Aq879364\*(Aq); \& my $verification_1 = $auth\->verify( \& \*(Aq879364\*(Aq, # code \& 1, # range \& \*(Aqutz4tl3bv5o3disb\*(Aq, # secret32 \& 1438643820, # timestamp (defaults to now) \& 30, # interval (default 30) \& ); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" This module provides a simplified interface to supporting typical two-factor authentication (i.e. \*(L"2FA\*(R") with Google Authenticator using the \&\s-1TOTP\s0 Algorithm as defined by \s-1RFC 6238\s0 . Although Google Authenticator supports both \s-1TOTP\s0 and \s-1HOTP,\s0 at the moment, this module only supports \s-1TOTP.\s0 .SH "METHODS" .IX Header "METHODS" The following are the supported methods of this module: .SS "new" .IX Subsection "new" This is a simple instantiator to which you can pass optional default values. .PP .Vb 1 \& my $auth = Auth::GoogleAuth\->new; \& \& $auth = Auth::GoogleAuth\->new({ \& secret => \*(Aqsome secret string thing\*(Aq, \& issuer => \*(AqGryphon Shafer\*(Aq, \& key_id => \*(Aqgryphon@cpan.org\*(Aq, \& }); .Ve .PP The object returned will support the following attribute get/set methods: .PP \fIsecret\fR .IX Subsection "secret" .PP This can be any string. It'll be used as the internal secret key to create the \s-1QR\s0 codes and authentication codes. .PP \fIsecret32\fR .IX Subsection "secret32" .PP This is a base\-32 encoded copy of the secret string. If this is left undefined and you run one of the methods that require it (like \f(CW\*(C`qr_code\*(C'\fR or \f(CW\*(C`code\*(C'\fR), the method called will try to create the \*(L"secret32\*(R" by looking for a value in \&\*(L"secret\*(R". If none exists, a random \*(L"secret32\*(R" will be generated. .PP \fIissuer\fR .IX Subsection "issuer" .PP This is the label name of the \*(L"issuer\*(R" of the authentication. See the key \s-1URI\s0 format wiki page for more information. .PP \fIkey_id\fR .IX Subsection "key_id" .PP This is the label name of the \*(L"key \s-1ID\*(R"\s0 of the authentication. See the key \s-1URI\s0 format wiki page for more information. .PP \fIotpauth\fR .IX Subsection "otpauth" .PP This method returns the otpauth key \s-1URI\s0 generated when you call \&\f(CW\*(C`qr_code\*(C'\fR. .SS "generate_secret32" .IX Subsection "generate_secret32" This method will generate a reasonable random \*(L"secret32\*(R" value, store it in the get/set method, and return it. .PP .Vb 1 \& my $secret32 = $auth\->generate_secret32; .Ve .SS "clear" .IX Subsection "clear" Given that the \*(L"secret\*(R" and \*(L"secret32\*(R" values may persist in this object, which could be a bad idea in some contexts, this \f(CW\*(C`clear\*(C'\fR method lets your clear out all attribute values. .PP .Vb 1 \& $auth\->clear; .Ve .SS "qr_code" .IX Subsection "qr_code" This method will return a Google Chart \s-1API URL\s0 that will return a \s-1QR\s0 code based on the data either in the object or provided to this method. .PP .Vb 6 \& my $url_0 = $auth\->qr_code; \& my $url_1 = $auth\->qr_code( \& \*(Aqbv5o3disbutz4tl3\*(Aq, # secret32 \& \*(Aqgryphon@cpan.org\*(Aq, # key_id \& \*(AqGryphon Shafer\*(Aq, # issuer \& ); .Ve .PP You can optionally add a final true value, and if you do, the method will return the generated otpauth key \s-1URI\s0 rather than the Google Chart \s-1API URL.\s0 .PP .Vb 3 \& my $url_2 = $auth\->qr_code( \& \*(Aqbv5o3disbutz4tl3\*(Aq, \*(Aqgryphon@cpan.org\*(Aq, \*(AqGryphon Shafer\*(Aq, 1, \& ); .Ve .SS "code" .IX Subsection "code" This method returns an authentication code, as if you were using Google Authenticator with the \*(L"secret32\*(R" value. .PP .Vb 1 \& my $code_0 = $auth\->code; .Ve .PP You can optionally pass override values similar to \f(CW\*(C`qr_code\*(C'\fR: .PP .Vb 5 \& my $code_1 = $auth\->code( \& \*(Aqutz4tl3bv5o3disb\*(Aq, # secret32 \& 1438643789, # timestamp (defaults to now) \& 30, # interval (default 30) \& ); .Ve .SS "verify" .IX Subsection "verify" This method is used for verification of codes entered by a user. Pass in the code (required) and optionally a range value and any override values. .PP .Vb 1 \& my $verification_0 = $auth\->verify(\*(Aq879364\*(Aq); .Ve .PP The range value is useful because the algorithm checks codes that are time\- based. If clocks are not exactly in sync, it's possible that a \*(L"nearly valid\*(R" code would be entered and should be accepted as valid but will be seen as invalid. By passing in an integer as a range value, you can stipulate how \&\*(L"fuzzy\*(R" the time should be. The default range is 0. A value of 1 will mean that a code based on a time 1 iteration plus or minus should verify. .PP .Vb 7 \& my $verification_1 = $auth\->verify( \& \*(Aq879364\*(Aq, # code \& 1, # range \& \*(Aqutz4tl3bv5o3disb\*(Aq, # secret32 \& 1438643820, # timestamp (defaults to now) \& 30, # interval (default 30) \& ); .Ve .SH "TYPICAL USE-CASE" .IX Header "TYPICAL USE-CASE" Typically, you're probably going to want to either randomly generate a secret or secret32 (\f(CW\*(C`generate_secret32\*(C'\fR) for a user and store it, or use a specific value or hash of some value as the secret. In either case, once you have a secret and its stored, generate a \s-1QR\s0 code (\f(CW\*(C`qr_code\*(C'\fR) for the user. You can alternatively provide the \*(L"secret32\*(R" to the user for them to manually enter it. That's it for setup. .PP To authenticate, present the user with a way to provide you a code (which will be a series of 6\-digits). Verify that code (\f(CW\*(C`verify\*(C'\fR) with either no range or some small range like 1. .SH "DEPENDENCIES" .IX Header "DEPENDENCIES" Digest::HMAC_SHA1, Math::Random::MT, URI::Escape, Convert::Base32, Class::Accessor, Carp. .SH "SEE ALSO" .IX Header "SEE ALSO" You can look for additional information about this module at: .IP "\(bu" 4 GitHub .IP "\(bu" 4 MetaCPAN .IP "\(bu" 4 GitHub Actions .IP "\(bu" 4 Codecov .IP "\(bu" 4 \&\s-1CPANTS\s0 .IP "\(bu" 4 \&\s-1CPAN\s0 Testers .PP You can look for additional information about things related to this module at: .IP "\(bu" 4 \&\s-1TOTP\s0 Algorithm .IP "\(bu" 4 \&\s-1RFC 6238\s0 .IP "\(bu" 4 Google Authenticator .IP "\(bu" 4 Google Authenticator GitHub .SH "AUTHOR" .IX Header "AUTHOR" Gryphon Shafer .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" This software is Copyright (c) 2015\-2021 by Gryphon Shafer. .PP This is free software, licensed under: .PP .Vb 1 \& The Artistic License 2.0 (GPL Compatible) .Ve