.\" 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 .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "LWP::Authen::OAuth2::Overview 3pm" .TH LWP::Authen::OAuth2::Overview 3pm "2021-01-11" "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" LWP::Authen::OAuth2::Overview \- Overview of accessing OAuth2 APIs with LWP::Authen::OAuth2 .SH "VERSION" .IX Header "VERSION" version 0.18 .SH "NAME" LWP::Authen::OAuth2::Overview \- Overview of accessing OAuth2 APIs with LWP::Authen::OAuth2 .SH "Introduction" .IX Header "Introduction" This attempts to be the document that I wished existed when I first tried to access an \s-1API\s0 that used OAuth 2 for authentication. It explains what OAuth 2 is, how it works, what you need to know to use it, and how LWP::Authen::OAuth2 tries to make that easier. It hopefully also explains this in a way which will help you read documentation written by other people who assume that you have this knowledge. .PP Feel free to read as much or little of this document as makes sense for you. It is not actually designed to be read in a single sitting. .PP Since part of the purpose of this document is to familiarize you with the jargon that you're likely to encounter, all terms commonly used in discussions of OAuth 2 with a specific meaning are \fIhighlighted\fR. Terms will hopefully be clear from context, but all highlighted terms are explained in the \*(L"Terminology\*(R" section. .SH "The Purpose of OAuth 2" .IX Header "The Purpose of OAuth 2" OAuth 2 makes it easy for large \fIservice provider\fRs to write many APIs that \&\fIuser\fRs can securely authorize third party \fIconsumer\fRs to use on their behalf. Everything good (and bad!) about the specification comes from this fact. .PP It therefore specifies an authorization handshake through which permissions are set up, and then a message signing procedure through which you can then access the \s-1API.\s0 Well, actually it specifies many variations of the authorization handshake, and multiple possible signing procedures, because large organizations run into a lot of use cases and try to cover them all. But conceptually they are all fundamentally similar, and so have been lumped together in one monster spec. .SH "The Purpose of LWP::Authen::OAuth2" .IX Header "The Purpose of LWP::Authen::OAuth2" LWP::Authen::OAuth2 exists to help Perl programmers who want to be a \&\fIconsumer\fR of an \s-1API\s0 protected by OAuth 2 to construct and make all of the necessary requests to the \fIservice provider\fR that you need to make. You will still need to set up your relationship with the \fIservice provider\fR, build your user interaction, manage private data (hooks are provided to make that straightforward), and figure out how to use the \s-1API.\s0 .PP If that does not sound like it will make your life easier, then this module is not intended for you. .PP If you are not a \fIconsumer\fR, this module is \fBdefinitely\fR not intended for you. (Though this document may still be helpful.) .SH "The Basic OAuth 2 Handshake" .IX Header "The Basic OAuth 2 Handshake" OAuth 2 allows a \fIuser\fR to tell a \fIservice provider\fR that a \fIconsumer\fR should be allowed to access the \fIuser\fR's data through an \s-1API.\s0 This permissioning happens through the following handshake. .PP The \fIconsumer\fR sends the \fIuser\fR to an \fIauthorization_url\fR managed by the \&\fIservice provider\fR. The \fIservice provider\fR tells the \fIuser\fR that the \&\fIconsumer\fR wants access to that account and asks if this is \s-1OK.\s0 The \fIuser\fR confirms that it is, and is sent back to the \fIconsumer\fR with proof of the conversation. The \fIconsumer\fR presents that proof to the \fIservice provider\fR along with proof that it actually is the \fIconsumer\fR, and is granted tokens that will act like keys to the \fIuser\fR's account. After that the \&\fIconsumer\fR can use said tokens to access the \s-1API\s0 which is protected by OAuth 2. .PP All variations of OAuth 2 follow this basic pattern. A large number of the details can and do vary widely. For example JavaScript applications that want to make \s-1AJAX\s0 calls use a different kind of proof. Applications installed on devices without web browsers will pass information to/from the user in different ways. And each \fIservice provider\fR is free to do many, many things differently. The specification tries to document commonalities in what different companies are doing, but does not mandate that they all do the same thing. .PP (This sort of complexity is inevitable from a specification that tries to make the lives of large \fIservice provider\fRs easy, and the lives of \&\fIconsumer\fRs possible.) .SH "Becoming a Consumer" .IX Header "Becoming a Consumer" If you want to access an OAuth 2 protected \s-1API,\s0 you need to become a \&\fIconsumer\fR. Here are the necessary steps, in the order that things happen in. .IP "Register with the \fIservice provider\fR" 4 .IX Item "Register with the service provider" You cannot access a \fIservice provider\fR without them knowing who you are. After you go through their process, at a minimum you will get a public \&\fIclient_id\fR, a private \fIclient_secret\fR, and have agreed on one or more \&\fIredirect_uri\fRs that the \fIuser\fR can use to deliver an \&\fIauthorization code\fR back to you. (That is not the only kind of proof that the \fIuser\fR can be given for the \fIconsumer\fR, but it is probably the only one that makes sense for a Perl \fIconsumer\fR.) .Sp The \fIredirect_uri\fR is often a \f(CW\*(C`https:///...\*(C'\fR \s-1URL\s0 under your control. You also are likely to have had to tell the \fIservice provider\fR about what type of software you're writing (webserver, command line, etc). This determines your \fIclient type\fR. They may call this a scenario, or \fIflow\fR, or something else. .Sp You will also need information about the \fIservice provider\fR. Specifically you will need to know their \fIAuthorization Endpoint\fR and \fIToken Endpoint\fR. They hopefully also have useful documentation about things like their APIs. .Sp LWP::Authen::OAuth2 is not directly involved in this step. .Sp If a LWP::Authen::OAuth2::ServiceProvider::Foo class exists, it should already have the \fIservice provider\fR specific information, and probably has summarized documentation that may make this smoother. If you're really lucky, there will be a \s-1CPAN\s0 module (or modules) for the \s-1API\s0 (or APIs) that you want to use. If those do not exist, please consider creating them. .Sp If no such classes exist, you can still use the module. Just pass the necessary \fIservice provider\fR facts in your call to \&\f(CW\*(C`LWP::Authen::OAuth2\->new(...)\*(C'\fR and an appropriate LWP::Authen::OAuth2::ServiceProvider will be created for you on the fly. .IP "Decide how to store sensitive information" 4 .IX Item "Decide how to store sensitive information" All of the data shared between you and the \fIservice provider\fR has to be stored on your end. This includes tokens that will let you access private information for the \fIuser\fR. You need to be able to securely store and access these. .Sp LWP::Authen::OAuth2 does not address this, beyond providing hooks that you are free to use as you see fit. .IP "Build interaction asking for \fIuser\fR permission" 4 .IX Item "Build interaction asking for user permission" You need to have some way of convincing the \fIuser\fR that they want to give you permission, ending in giving them an \fIauthorization_url\fR which sends them off to the \fIservice provider\fR to authorize access. This interaction can range from a trivial conversation with yourself if you are the only \&\fIuser\fR you will be handling, to a carefully thought through sales pitch if you are trying to get members of the public to sign up. .Sp LWP::Authen::OAuth2 helps you build that \s-1URL.\s0 The rest is up to you. .IP "Build interaction receiving your \fIauthorization code\fR" 4 .IX Item "Build interaction receiving your authorization code" When the \fIuser\fR finishes their interaction with the \fIservice provider\fR, if the \fIservice provider\fR is sure that they know where to send the user (they know your \fIclient_id\fR, your \fIredirect_uri\fR makes sense to them) then they will be sent to the \fIredirect_uri\fR to pass information back to you. .Sp If you succeeded, you will receive a \fIcode\fR in some way. For instance if your \fIredirect_uri\fR is a \s-1URL,\s0 it will have a get parameter named \f(CW\*(C`code\*(C'\fR. .Sp You could get an \f(CW\*(C`error\*(C'\fR parameter back instead. See \&\s-1RFC 6749\s0 for a list of the possible errors. Note that there are possible optional fields with extra detail. I would not advise optimism about their presence. .Sp LWP::Authen::OAuth2 is not involved with this. .IP "Request tokens" 4 .IX Item "Request tokens" Once you have that \fIcode\fR you are supposed to immediately trade it in for tokens. LWP::Authen::OAuth2 provides the \f(CW\*(C`request_tokens\*(C'\fR method to do this for you. Should you not actually get tokens, then the \&\f(CW\*(C`request_tokens\*(C'\fR method will trigger an error. .Sp \&\fB\s-1NOTE\s0\fR that the \fIcode\fR cannot be expected to work more than once. Nor can you expect the \fIservice provider\fR to repeatedly hand out working \fIcode\fRs for the same permission. (The qualifier \*(L"working\*(R" matters.) Being told this will hopefully let you avoid a painful debugging session that I did not enjoy. .IP "Save and pass around tokens (maybe)" 4 .IX Item "Save and pass around tokens (maybe)" If you will need access to information in multiple locations (for instance on several different web pages), then you are responsible for saving and retrieving those tokens for future use. LWP::Authen::OAuth2 makes it easy to serialize/deserialize tokens, and has hooks for when they change, but leaves this step up to you. .IP "Access the \s-1API\s0" 4 .IX Item "Access the API" LWP::Authen::OAuth2 takes care of signing your \s-1API\s0 requests. What requests you need to actually make are between you and the \&\fIservice provider\fR. With luck there will be documentation to help you figure it out, and if you are really lucky that will be reasonably accurate. .IP "Refresh access tokens (maybe)" 4 .IX Item "Refresh access tokens (maybe)" The \fIaccess token\fR that is used to sign requests will only work for a limited time. If you were given a \fIrequest token\fR, that can be used to request another \fIaccess token\fR at any time. Which raises the possibility that you make a request, it fails because the \fIaccess token\fR expired, you refresh it, then need to retry your request. .Sp LWP::Authen::OAuth2 will perform this refresh/retry logic for you automatically if possible, and provides a hook for you to know to save the updated token data. .Sp Some \fIclient type\fRs are not expected to use this pattern. You are only given an \fIaccess token\fR and are expected to send the user through the handshake again when that expires. The second time through the redirect on the \fIservice provider\fR's side is immediate, so the user experience should be seamless. However LWP::Authen::OAuth2 does not try to automate that logic. But \f(CW\*(C`$oauth2\->should_refresh\*(C'\fR can let you know when it is time to send the user through, and \f(CW\*(C`$oauth2\->can_refresh_tokens\*(C'\fR will let you know whether automatic refreshing is available. .Sp Note that even if it is available, retry success is not guaranteed. The \&\fIuser\fR may revoke your access, the \fIservice provider\fR may decide you are a suspicious character, there may have been a service outage, etc. LWP::Authen::OAuth2 will throw errors on these error conditions, handling them is up to you. .SH "Terminology" .IX Header "Terminology" This section is intended to be used in one of two ways. .PP The first option is that you can start reading someone else's documentation and then refer back to here every time you run across a term that you do not immediately understand. .PP The second option is that you can read this section straight through for a reasonably detailed explanation of the OAuth 2 protocol, with all terms explained. In fact if you choose this option, you will find it explained in more detail than you need to be a successful \fIconsumer\fR. .PP However if you use it in the second way, please be advised that this does not try to be a complete and exact explanation of the specification. In particular the specification requires specific error handling from the service provider that I have glossed over, and allows for extra types of requests that I also glossed over. (Particularly the bit about how any \&\fIservice provider\fR at any time can add any new method that they want so long as they invent a new \fIgrant_type\fR for it.) .IP "consumer" 4 .IX Item "consumer" The \fIconsumer\fR is the one who needs to be authorized by OAuth 2 to be able to \*(L"consume\*(R" an \s-1API.\s0 If you're reading this document, that's likely to be you. .IP "client" 4 .IX Item "client" The software on the \fIconsumer\fR's side which actually will access the \s-1API.\s0 From a \fIconsumer\fR's point of view, a \fIconsumer\fR and the \fIclient\fR are usually the same thing. But, in fact, a single \fIconsumer\fR may actually write multiple \fIclient\fRs. And if one is a web application while another is a command line program, the differences can matter to how OAuth 2 will work. .Sp Where I have a choice in this document I say \fIconsumer\fR rather than \&\fIclient\fR because that term is less likely overloaded in most organizations. .IP "user" 4 .IX Item "user" The \fIuser\fR is the entity (person or company) who wishes to let the \&\fIconsumer\fR access their account. .IP "Resource Owner" 4 .IX Item "Resource Owner" What the OAuth 2 specification calls the \fIuser\fR, to focus attention on the fact that they own the data which will get accessed. .Sp I chose to say \fIuser\fR instead of \fIResource Owner\fR because that is my best guess as to what the \fIconsumer\fR is most likely to already call them. .IP "service provider" 4 .IX Item "service provider" The \fIservice provider\fR is the one which hosts the account, restricts access and offers the \s-1API.\s0 For example, Google. .IP "Resource Server" 4 .IX Item "Resource Server" In the OAuth 2 specification, this is the service run by the \&\fIservice provider\fR which hosts provides an \s-1API\s0 to the user's data. The name has deliberate symmetry with \fIResource Owner\fR. .IP "Authorization Server" 4 .IX Item "Authorization Server" In the OAuth 2 specification, this is the service run by the \&\fIservice provider\fR which is responsible for granting access to the \&\fIResource Server\fR. .Sp The \fIconsumer\fR does not need to care about this distinction, but it exposes an important fact about how the \fIservice provider\fR is likely to be structured internally. You typically will have one team that is responsible for granting access, tracking down \fIclient\fRs that seem abusive, and so on. And then many teams are free to create useful stuff and write APIs around them, with authorization offloaded to the first team. .Sp As a \fIconsumer\fR, you will make \s-1API\s0 requests to the \fIResource Server\fR signed with proof of auhorization from the \fIAuthorization Server\fR, the \&\fIResource Server\fR will confirm authorization with the \&\fIAuthorization Server\fR, and then the \fIResource Server\fR will do whatever it was asked to do. .Sp Organizing internal responsibilities in this manner makes it easier for many independent teams in a large company to write public APIs. .IP "client type" 4 .IX Item "client type" The \fIservice provider\fR internally tags each \fIclient\fR with a \fIclient type\fR which tells it something about what environment it is in, and how it interacts with the \fIuser\fR. Are are the basic types listed in \&\s-1RFC 6749\s0 : .RS 4 .IP "web application" 4 .IX Item "web application" Runs on a web server. Is expected to keep secrets. Likely to be appropriate for a Perl \fIclient\fR. .IP "user-agent-based application" 4 .IX Item "user-agent-based application" JavaScript application running in a browser that wants to make \s-1AJAX\s0 calls. Can't keep secrets. Does not make sense for A Perl \fIclient\fR. .IP "native application" 4 .IX Item "native application" Application installed on a \fIuser\fR's machine. Can't keep secrets. Possibly appropriate for a Perl \fIclient\fR. .RE .RS 4 .Sp Of course all of this is up to the \fIservice provider\fR. For example at the time of this writing, Google documents no less than six \fIclient type\fRs at , none of which have been given the above names. (They also call them \*(L"Scenarios\*(R" rather than \&\fIclient type\fR.) They rename the top two, split \fInative application\fR into two based on whether your application controls a browser, and add two new ones. .RE .IP "flow" 4 .IX Item "flow" Your \fIflow\fR is the sequence and methods of interactions that set up authorization. The \fIflow\fR depends on your \fIservice provider\fR and \&\fIclient type\fR. For example the \fIservice provider\fR might redirect the \&\fIuser\fR to a \s-1URL\s0 controlled by a web application, while instead for a native application the user is told to cut and paste a code somewhere. .Sp Despite \fIflow\fR being more common terminology in OAuth 2, \fIclient type\fR is more self-explanatory, so I've generally gone with that instead. .IP "client_id" 4 .IX Item "client_id" The \fIclient_id\fR is a public \s-1ID\s0 that tells the \fIservice provider\fR about the \&\fIclient\fR that is accessing it. That is, it says both who the \fIconsumer\fR is, and what the \fIclient type\fR is. Being public, the \fIclient_id\fR can be shared with the \fIuser\fR. The details of how this is assigned are between the \&\fIconsumer\fR and the \fIservice provider\fR. .IP "client_secret" 4 .IX Item "client_secret" The \fIclient_secret\fR is a somewhat private piece of information that the \&\fIconsumer\fR can pass to the \fIservice provider\fR to prove that the request really comes from the \fIconsumer\fR. How much this is trusted, and how it is used, will depend on the \fIclient type\fR and \fIservice provider\fR. .IP "redirect_uri" 4 .IX Item "redirect_uri" The \fIservice provider\fR needs a way to tell the \fIuser\fR how to pass information back to the \fIconsumer\fR in a secure way. That is provided by the \&\fIredirect_uri\fR which can be anything from a \f(CW\*(C`https://...\*(C'\fR \s-1URL\s0 that the \&\fIconsumer\fR controls to an instruction that lets the \fIservice provider\fR know that it should tell the \fIuser\fR to cut and paste some information. .Sp It is up to the \fIservice provider\fR what values of are acceptable for the \&\fIredirect_uri\fR, and whether it is a piece of information that is remembered or passed in during the authorization process. .IP "state" 4 .IX Item "state" The \fIstate\fR is an optional piece of information that can be created by the \&\fIconsumer\fR then added to all requests as an extra piece of protection against forgery. (You are supposed to create a random piece of information for each request, then check that you get it back.) In the OAuth 2 specification it is optional, but recommended. Depending on the combination of your \fIservice provider\fR and \fIclient type\fR, it may be required. .IP "scope" 4 .IX Item "scope" The \fIscope\fR describes what permissions are to be granted. To get multiple permissions, you need to join the permissions requested with spaces. Everything else is up to the \fIservice provider\fR. .Sp Inside of the \fIservice provider\fR, what likely happens is that the team which runs a given \fIResource Server\fR tells the team running the \&\fIAuthorization Server\fR what permissions to their \s-1API\s0 should be called. And then the \fIAuthorization Server\fR can limit a given \fIconsumer\fR to just the APIs that the \fIuser\fR authorized them for. .IP "Authorization Endpoint" 4 .IX Item "Authorization Endpoint" The \fIAuthorization Endpoint\fR is the \s-1URL\s0 provided by the \fIservice provider\fR for the purpose of sending requests to authorize the \fIconsumer\fR to access the \fIuser\fR's account. This is part of the \fIAuthorization Server\fR. .IP "response_type" 4 .IX Item "response_type" The \fIresponse_type\fR tells the \fIservice provider\fR what kind of information it is supposed to pass back. I am not aware of a case where a Perl \fIclient\fR could usefully use any value other than \f(CW\*(C`code\*(C'\fR. However there are \fIflow\fRs where other things happen. For example the \fIflow\fR for the \&\fIuser-agent-based application\fR \fIclient type\fR uses a \fIresponse_type\fR of \&\fItoken\fR. .Sp While the field is not very useful for Perl \fIclient\fRs, it is required in the specification. So you have to pass it. .IP "authorization_url" 4 .IX Item "authorization_url" This is the \s-1URL\s0 on the \fIservice provider\fR's website that the \fIuser\fR goes to in order to let the \fIservice provider\fR know what authorization is being requested. .Sp It is constructed as the \fIAuthorization Endpoint\fR with get parameters added for the \fIresponse_type\fR, \fIclient_id\fR, and optionally \fIstate\fR. The specification mentions both \fIredirect_uri\fR and \fIscope\fR but does not actually mandate that they be accepted or required. However they may be. And, of course, a given service provider can add more parameters at will, and require (or not) different things by \fIclient type\fR. .Sp An example \s-1URL\s0 for Google complete with optional extensions is .Sp In LWP::Authen::OAuth2 the \f(CW\*(C`authorization_url\*(C'\fR method constructs this \&\s-1URL.\s0 If your request needs to include the \fIstate\fR, \fIscope\fR, or any \&\fIservice provider\fR specific parameter, you need to pass those as parameters. The others are usefully defaulted from the service provider and object. .IP "(authorization) code" 4 .IX Item "(authorization) code" If the \fIresponse_type\fR is set to \f(CW\*(C`code\*(C'\fR (which should be the case), then on success the \fIservice provider\fR will generate a one use \fIauthorization code\fR to give to the user to take back to the \fIconsumer\fR. Depending on the \&\fIflow\fR this could happen with no effort on the part of the \fIuser\fR. For example the \fIuser\fR can be redirected to the \fIredirect_uri\fR with the \fIcode\fR passed as a get parameter. The web server would then pick these up, finish the handshake, and then redirect the user elsewhere. .Sp In all interactions where it is passed it is simply called the \fIcode\fR. But it is described in one interaction as an \fIauthorization_code\fR. .IP "Token Endpoint" 4 .IX Item "Token Endpoint" The \fIToken Endpoint\fR is the \s-1URL\s0 provided by the \fIservice provider\fR for the purpose of sending requests from the \fIconsumer\fR to get tokens allowing access to the \fIuser\fR's account. .IP "grant_type" 4 .IX Item "grant_type" The \fIgrant_type\fR is the type of grant you expected to get based on the \&\fIresponse_type\fR requested in the \fIauthorization_url\fR. For a \&\fIresponse_type\fR of \f(CW\*(C`code\*(C'\fR (which is almost certainly what will be used with any \fIconsumer\fR written in Perl), the \fIgrant_type\fR has to be \&\f(CW\*(C`authorization_code\*(C'\fR. If they were being consistent, then that would be \&\fIcode\fR like it is everywhere else, but that's what the spec says. .Sp We will later encounter the \fIgrant_type\fR \f(CW\*(C`refresh_token\*(C'\fR. The specification includes potential requests that can be in a \fIflow\fR that might prove useful. However you are only likely to encounter that if you are subclassing LWP::Authen::OAuth2::ServiceProvider. In that case you will hopefully discover the applicability and details of those \fIgrant_type\fRs from the \fIservice provider\fR's documentation. .IP "Access Token Request" 4 .IX Item "Access Token Request" Once the \fIconsumer\fR has a \fIcode\fR the consumer can submit an \&\fIAccess Token Request\fR by sending a \s-1POST\s0 request to the \&\fIToken Endpoint\fR with the \fIgrant_type\fR, \fIcode\fR, \fIclient_id\fR, \&\fIclient_secret\fR, \fIredirect_uri\fR and (if in the authorization code) the \fIstate\fR. Your \fIservice provider\fR can also require you to authenticate in any further way that they please. You will get back a \s-1JSON\s0 response. .Sp An example request might look like this: .Sp .Vb 3 \& POST /o/oauth2/token HTTP/1.1 \& Host: accounts.google.com \& Content\-Type: application/x\-www\-form\-urlencoded \& \& code=4/P7q7W91a\-oMsCeLvIaQm6bTrgtp7& \& client_id=8819981768.apps.googleusercontent.com& \& client_secret={client_secret}& \& redirect_uri=https://oauth2\-login\-demo.appspot.com/code& \& grant_type=authorization_code .Ve .Sp and the response if you're lucky will look something like: .Sp .Vb 4 \& HTTP/1.1 200 OK \& Content\-Type: application/json;charset=UTF\-8 \& Cache\-Control: no\-store \& Pragma: no\-cache \& \& { \& "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", \& "expires_in":3920, \& "token_type":"Bearer", \& "refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C\-259HOF2aQbI" \& } .Ve .Sp or if you're unlucky, maybe like this: .Sp .Vb 4 \& HTTP/1.1 200 OK \& Content\-Type: application/json;charset=UTF\-8 \& Cache\-Control: no\-store \& Pragma: no\-cache \& \& { \& "error":"invalid_grant" \& } .Ve .Sp Success is up to the \fIservice provider\fR which can decide not to give you tokens for any reason that they want, including that you asked twice, they think the \fIuser\fR might be compromised, they don't like the \fIclient\fR, or the phase of the Moon. (I am not aware of any \fIservice provider\fR that makes failure depend on the phase of the Moon, but the others are not made up.) .Sp The \f(CW\*(C`request_tokens\*(C'\fR method of LWP::Authen::OAuth2 will make this request for you, read the \s-1JSON\s0 and create the token or tokens. If you passed in a \f(CW\*(C`save_tokens\*(C'\fR callback in constructing your object, that will be called for you to store the tokens. On future \s-1API\s0 calls you can retrieve that to skip the handshake if possible. .IP "token_type" 4 .IX Item "token_type" The \fItoken_type\fR is a case insensitive description of the type of token that you could be given. In theory there is a finite list of types that you could encounter. In practice \fIservice provider\fRs can add more at any time, either intentionally or unintentionally by failing to correctly implement the one that they claimed to have created. .Sp See LWP::Authen::OAuth2::AccessToken for advice on how to add support for a new or incorrectly implemented \fItoken_type\fR. .IP "expires_in" 4 .IX Item "expires_in" The number of seconds until you will need a new token because the old one should have expired. LWP::Authen::OAuth2 provides the \f(CW\*(C`should_refresh\*(C'\fR method to let you know when you need that new token. (It actually starts returning true slightly early to avoid problems if clocks are not synchronized, or you begin a series of operations.) .IP "access_token" 4 .IX Item "access_token" An \fIaccess_token\fR is a temporary token that gives the \fIconsumer\fR access to the \fIuser\fR's data in the \fIservice provider\fR's system. In the above response the \f(CW\*(C`access_token\*(C'\fR is the value of the token, \f(CW\*(C`expires_in\*(C'\fR is the number of seconds it is good for in theory (practice tends to be close but not always exact), and \f(CW\*(C`token_type\*(C'\fR specifies how it is supposed to be used. .Sp Once the authorization handshake is completed, if the \fIaccess_token\fR has a supported \fItoken_type\fR. then LWP::Authen::OAuth2 will automatically sign any requests for you. .IP "Bearer token" 4 .IX Item "Bearer token" If the \fItoken_type\fR is \f(CW\*(C`bearer\*(C'\fR (case insensitive), then you should have a \&\fIbearer token\fR as described by \&\s-1RFC 6750\s0 . For as long as the token is good, any request signed with it is authorized. Signing is as simple as sending an https request with a header of: .Sp .Vb 1 \& Authorization: Bearer 1/fFAGRNJru1FTz70BzhT3Zg .Ve .Sp You can also sign by passing \f(CW\*(C`access_token=...\*(C'\fR as a post or get parameter, though the specification recommends against using a get parameter. If you are using LWP::Authen::OAuth2, then it is signed with the header. .IP "refresh_token" 4 .IX Item "refresh_token" The above example also included a \fIrefresh_token\fR. If you were given one, you can use it later to ask for a refreshed \fIaccess_token\fR. Whether you get one is up to your \fIservice provider\fR, who is likely to decide that based on your \fIclient_type\fR. .IP "Refresh Access Token" 4 .IX Item "Refresh Access Token" If you have a \fIrefresh_token\fR, you can at any time send a \&\fIRefresh Access Token\fR request. This is a \s-1POST\s0 to the \fIToken Endpoint\fR with the \fIrefresh_token\fR, \fIclient_id\fR and \fIclient_secret\fR arguments. You also have to send a \fIgrant_type\fR of \f(CW\*(C`refresh_token\*(C'\fR. .Sp Thus in the above case we'd send .Sp .Vb 3 \& POST /o/oauth2/token HTTP/1.1 \& Host: accounts.google.com \& Content\-Type: application/x\-www\-form\-urlencoded \& \& refresh_token=1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C\-259HOF2aQbI& \& client_id=8819981768.apps.googleusercontent.com& \& client_secret={client_secret}& \& grant_type=refresh_token .Ve .Sp and if lucky could get a response like .Sp .Vb 4 \& HTTP/1.1 200 OK \& Content\-Type: application/json;charset=UTF\-8 \& Cache\-Control: no\-store \& Pragma: no\-cache \& \& { \& "access_token":"ya29.AHES6ZSiArSow0zeKokajrri5gMBpGc6Sq", \& "expires_in":3600, \& "token_type":"Bearer", \& } .Ve .Sp and if unlucky could get an error as before. .Sp In LWP::Authen::OAuth2 this request is made for you transparently behind the scenes if possible. If you're curious when, look in the source for the \&\f(CW\*(C`refresh_access_token\*(C'\fR method. There are also optional callbacks that you can pass to let you save the tokens, or hijack the refresh method for your own purposes. (Such as making sure that only one process tries to refresh tokens even though many are accessing it.) .Sp But note that not all \fIflow\fRs offer a \fIrefresh_token\fR. If you're on one of those \fIflow\fRs then you need to send the \fIuser\fR back to the \&\fIservice provider\fR for authorization renewal. From the \fIuser\fR's point of view this is likely to be painless because it will be done with transparent redirects. But the \fIconsumer\fR needs to be aware of it. .SH "AUTHORS" .IX Header "AUTHORS" .IP "\(bu" 4 Ben Tilly, .IP "\(bu" 4 Thomas Klausner .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" This software is copyright (c) 2013 \- 2021 by Ben Tilly, Rent.com, Thomas Klausner. .PP This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.