-
Notifications
You must be signed in to change notification settings - Fork 289
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create a new oauth2 package for functionality to work with OAuth2. This package will be used to authenticate CLI clients with the BSR. The current functionality is limited to declaring types for use with the device authorization grants flow.
- Loading branch information
1 parent
e6e590b
commit 02437af
Showing
4 changed files
with
259 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
// 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"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// 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 contains functionality to work with OAuth2. | ||
package oauth2 | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
// ErrorCode is an OAuth2 error code. | ||
type ErrorCode string | ||
|
||
// The following error codes are defined by RFC 6749 Section 5.2 Error Response. | ||
const ( | ||
// ErrorCodeInvalidRequest is an invalid or malformed request error. | ||
ErrorCodeInvalidRequest ErrorCode = "invalid_request" | ||
// ErrorCodeInvalidClient is a client authentication error. | ||
ErrorCodeInvalidClient ErrorCode = "invalid_client" | ||
// ErrorCodeInvalidGrant is an invalid grant error. | ||
ErrorCodeInvalidGrant ErrorCode = "invalid_grant" | ||
// ErrorCodeUnauthorizedClient is an unauthorized client error. | ||
ErrorCodeUnauthorizedClient ErrorCode = "unauthorized_client" | ||
// ErrorCodeUnsupportedGrantType is an unsupported grant type error. | ||
ErrorCodeUnsupportedGrantType ErrorCode = "unsupported_grant_type" | ||
// ErrorCodeInvalidScope is an invalid scope error. | ||
ErrorCodeInvalidScope ErrorCode = "invalid_scope" | ||
) | ||
|
||
// Error is an OAuth2 error. | ||
type Error struct { | ||
// ErrorCode is the error code. | ||
ErrorCode ErrorCode `json:"error"` | ||
// ErrorDescription is a human-readable description of the error. May be empty. | ||
ErrorDescription string `json:"error_description,omitempty"` | ||
// ErrorURI is a URI for the error. May be empty. | ||
ErrorURI string `json:"error_uri,omitempty"` | ||
} | ||
|
||
// Error implements error. | ||
func (e *Error) Error() string { | ||
if e == nil { | ||
return "" | ||
} | ||
s := fmt.Sprintf("oauth2: %q", e.ErrorCode) | ||
if e.ErrorDescription != "" { | ||
s += fmt.Sprintf(" %q", e.ErrorDescription) | ||
} | ||
if e.ErrorURI != "" { | ||
s += fmt.Sprintf(" %q", e.ErrorURI) | ||
} | ||
return s | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.