blob: dc440c1be96a4f72f680a2ac6c8c940a1fe1ce73 [file] [edit]
// Copyright 2020-2024 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package oauth2
import (
"net/url"
)
const (
// DeviceRegistrationPath is the path for the device registration endpoint.
DeviceRegistrationPath = "/oauth2/device/registration"
// DeviceAuthorizationPath is the path for the device authorization endpoint.
DeviceAuthorizationPath = "/oauth2/device/authorization"
// DeviceTokenPath is the path for the device token endpoint.
DeviceTokenPath = "/oauth2/device/token"
)
const (
// DeviceAuthorizationGrantType is the grant type for the device authorization flow.
DeviceAuthorizationGrantType = "urn:ietf:params:oauth:grant-type:device_code"
)
// The following error codes are defined by RFC 8628 Section 3.5 Device Authorization Response.
const (
// ErrorCodeAuthorizationPending is a pending device authorization grant as the
// end user hasn't yet completed the user interaction steps.
ErrorCodeAuthorizationPending ErrorCode = "authorization_pending"
// ErrorCodeSlowDown is returned for a pending device authorization grant and
// polling should continue, but the interval MUST be increased by 5 seconds for
// all subsequent requests.
ErrorCodeSlowDown ErrorCode = "slow_down"
// ErrorCodeAccessDenied is returned when the device authorization request was denied.
ErrorCodeAccessDenied ErrorCode = "access_denied"
// ErrorCodeExpiredToken is the device_code has expired, and the device authorization
// session has concluded. The client MAY commence a new device authorization request but
// SHOULD wait for user interaction before restarting to avoid unnecessary polling.
ErrorCodeExpiredToken ErrorCode = "expired_token"
)
// DeviceRegistrationRequest describes an OpenID Connect Dynamic Client Registration 1.0 request
// for dynamic client registration. It is a subset of the full specification.
// It does not require a redirect URI or grant types for the device authorization flow.
// https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationRequest
type DeviceRegistrationRequest struct {
// Name of the client to be presented to the end user.
ClientName string `json:"client_name"`
}
// Devic describes a successful OpenID Connect Dynamic Client Registration 1.0 response
// for dynamic client registration.
type DeviceRegistrationResponse struct {
// ClientID is the unique client identifier.
ClientID string `json:"client_id"`
// ClientSecret is the client secret. May be empty.
ClientSecret string `json:"client_secret,omitempty"`
// ClientIDIssuedAt is the time at which the ClientID was issued in seconds since the Unix epoch.
ClientIDIssuedAt int `json:"client_id_issued_at"`
// ClientSecretExpiresAt is the time at which the client_secret will expire in seconds since the Unix epoch.
ClientSecretExpiresAt int `json:"client_secret_expires_at,omitempty"`
}
// DeviceAuthorizationRequest describes an RFC 8628 Device Authorization Request.
// https://datatracker.ietf.org/doc/html/rfc8628#section-3.1
type DeviceAuthorizationRequest struct {
// ClientID is the unique client identifier.
ClientID string `json:"client_id"`
// ClientSecret is the client secret. May be empty.
ClientSecret string `json:"client_secret,omitempty"`
}
// ToValues converts the DeviceAuthorizationRequest to url.Values.
func (d *DeviceAuthorizationRequest) ToValues() url.Values {
values := make(url.Values, 2)
values.Set("client_id", d.ClientID)
if d.ClientSecret != "" {
values.Set("client_secret", d.ClientSecret)
}
return values
}
// FromValues converts the url.Values to a DeviceAuthorizationRequest.
func (d *DeviceAuthorizationRequest) FromValues(values url.Values) error {
d.ClientID = values.Get("client_id")
d.ClientSecret = values.Get("client_secret")
return nil
}
// DeviceAuthorizationResponse describes a successful RFC 8628 Device Authorization Response
// https://datatracker.ietf.org/doc/html/rfc8628#section-3.2
type DeviceAuthorizationResponse struct {
// DeviceCode is the device verification code.
DeviceCode string `json:"device_code"`
// UserCode is the end-user verification code.
UserCode string `json:"user_code"`
// VerificationURI is the verification URI that the end user should visit to
// enter the user_code.
VerificationURI string `json:"verification_uri"`
// VerificationURIComplete is the verification URI that includes the user_code.
VerificationURIComplete string `json:"verification_uri_complete,omitempty"`
// ExpiresIn is the lifetime in seconds of the "device_code" and "user_code".
ExpiresIn int `json:"expires_in"`
// Interval is the minimum amount of time in seconds that the client SHOULD wait
// between polling requests to the token endpoint.
Interval int `json:"interval,omitempty"`
}
// DeviceAccessTokenRequest describes an RFC 8628 Device Token Request.
// https://datatracker.ietf.org/doc/html/rfc8628#section-3.4
type DeviceAccessTokenRequest struct {
// ClientID is the client identifier issued to the client during the registration process.
ClientID string `json:"client_id"`
// ClientSecret is the client secret. May be empty.
ClientSecret string `json:"client_secret,omitempty"`
// DeviceCode is the device verification code.
DeviceCode string `json:"device_code"`
// GrantType is the grant type for the device authorization flow. Must be
// set to "urn:ietf:params:oauth:grant-type:device_code".
GrantType string `json:"grant_type"`
}
// ToValues converts the DeviceTokenRequest to url.Values.
func (d *DeviceAccessTokenRequest) ToValues() url.Values {
values := make(url.Values, 4)
values.Set("client_id", d.ClientID)
if d.ClientSecret != "" {
values.Set("client_secret", d.ClientSecret)
}
values.Set("device_code", d.DeviceCode)
values.Set("grant_type", d.GrantType)
return values
}
// FromValues converts the url.Values to a DeviceTokenRequest.
func (d *DeviceAccessTokenRequest) FromValues(values url.Values) error {
d.ClientID = values.Get("client_id")
d.ClientSecret = values.Get("client_secret")
d.DeviceCode = values.Get("device_code")
d.GrantType = values.Get("grant_type")
return nil
}
// DeviceAccessTokenResponse describes a successful RFC 8628 Device Token Response.
// https://datatracker.ietf.org/doc/html/rfc8628#section-3.5
type DeviceAccessTokenResponse struct {
// AccessToken is the access token that can be used to access the protected resources.
AccessToken string `json:"access_token"`
// TokenType is the type of the token issued as described in RFC 6749 Section 7.1.
// https://datatracker.ietf.org/doc/html/rfc6749#section-7.1
TokenType string `json:"token_type"`
// ExpiresIn is the lifetime in seconds of the access token.
ExpiresIn int `json:"expires_in,omitempty"`
// RefreshToken may be used to obtain new access tokens using the same authoization
// grant. May be empty.
RefreshToken string `json:"refresh_token,omitempty"`
// Scope is the scope of the access token as described in RFC 6749 Section 3.3.
// https://datatracker.ietf.org/doc/html/rfc6749#section-3.3
Scope string `json:"scope,omitempty"`
}