Documentation
¶
Index ¶
- Constants
- Variables
- func BearerTokenHandler(unguardedRoute []string, GuardedRouteGroups []string, ErrorLogger *log.Logger, ...) func(next http.Handler) http.Handler
- func ChallengeCodeValidate(challengeCode, method string) (bool, error)
- func GenerateTokenExpiry(hours int) time.Time
- func IsExpired(token interface{}) bool
- func ScopeHandler(UnguardedRoutes []string, GuardedRouteGroups []string, ErrorLogger *log.Logger, ...) func(next http.Handler) http.Handler
- type AuthorizationResponse
- type AuthorizationToken
- type Client
- type Configuration
- type ErrorResponse
- type OauthResponse
- type OauthToken
- type RedirectUri
- type RefreshToken
- type Scopes
- type Service
- func (o *Service) AccessTokenGrantExchange(w http.ResponseWriter, r *http.Request) (*OauthResponse, *ErrorResponse)
- func (o *Service) AnyScope(r *http.Request, anyScopes Scopes) bool
- func (o *Service) AuthenticateToken(r *http.Request) (bool, *OauthToken, error)
- func (o *Service) AuthenticationCheckForScopes() func(next http.Handler) http.Handler
- func (o *Service) AuthenticationTokenMiddleware() func(next http.Handler) http.Handler
- func (o *Service) AuthorizationClientCodeExchange(w http.ResponseWriter, r *http.Request, client *Client) (*AuthorizationResponse, *ErrorResponse)
- func (o *Service) AuthorizationClientCodeExchangeImplicit(w http.ResponseWriter, r *http.Request, client *Client) (*AuthorizationResponse, *ErrorResponse)
- func (o *Service) AuthorizationClientExchange(w http.ResponseWriter, r *http.Request, client *Client) (*AuthorizationResponse, *ErrorResponse)
- func (o *Service) AuthorizationGrantExchange(w http.ResponseWriter, r *http.Request) (*AuthorizationResponse, *ErrorResponse)
- func (o *Service) AuthorizationGrantExchangePost(w http.ResponseWriter, r *http.Request) (*AuthorizationResponse, *ErrorResponse)
- func (o *Service) CheckUserPasswordMatches(plainText string, user User) bool
- func (o *Service) ConsumeAuthorizationToken(plainText string) (*AuthorizationToken, error)
- func (o *Service) DeleteAuthorizationToken(id int) error
- func (o *Service) DeleteOauthToken(id int) error
- func (o *Service) DeleteRefreshTokenByToken(plainText string) error
- func (o *Service) GenerateAuthorizationToken() (*AuthorizationToken, error)
- func (o *Service) GenerateOauthToken() (*OauthToken, error)
- func (o *Service) GenerateRefreshToken(userID int, AccessTokenID int, clientID int) (*RefreshToken, error)
- func (o *Service) GetAuthTokenFromHeader(r *http.Request) (*OauthToken, error)
- func (o *Service) GetAuthenticatedUser(r *http.Request) *User
- func (o *Service) GetAuthorizationTokenByToken(plainText string) (*AuthorizationToken, error)
- func (o *Service) GetByToken(plainText string) (*OauthToken, error)
- func (o *Service) GetClient(id int) (*Client, error)
- func (o *Service) GetOauthToken(id int) (*OauthToken, error)
- func (o *Service) GetRefreshByToken(plainText string) (*RefreshToken, error)
- func (o *Service) GetUserByEmail(email string) (*User, error)
- func (o *Service) HasScope(r *http.Request, requiredScopes Scopes) bool
- func (o *Service) InsertAuthorizationToken(token *AuthorizationToken) (*AuthorizationToken, error)
- func (o *Service) InsertClient(client Client) (*Client, error)
- func (o *Service) InsertOauthToken(token *OauthToken) (*OauthToken, error)
- func (o *Service) InsertRefreshToken(token *RefreshToken) error
- func (o *Service) RefreshTokenExchange(w http.ResponseWriter, r *http.Request) (*OauthResponse, *ErrorResponse)
- func (o *Service) ResourceOwnerTokenExchange(r *http.Request, w http.ResponseWriter, client Client) (*OauthToken, *RefreshToken, *ErrorResponse)
- func (o *Service) TokenIsExpired(token interface{}) bool
- func (o *Service) UserIsLoggedIn(r *http.Request) bool
- func (o *Service) ValidateClientRedirect(uri string, client *Client) bool
- func (o *Service) VerifyAuthorizationCode(token AuthorizationToken, codeVerifier string) bool
- type User
Constants ¶
const ( FlowPlain = "plain" FlowPKCE = "pkce" FlowPKCEImplicit = "pkce_implicit" FlowVerify = "verify" )
Flow constants for authorization_code client sub-flows.
Variables ¶
var ( // ContextKeyAccessToken is the plaintext bearer token, populated by // BearerTokenHandler after successful token validation. Promoted to a // typed key for type-safe consumer access; the legacy string key // "accessToken" is still set for one major release for backward compat. ContextKeyAccessToken = contextKey{/* contains filtered or unexported fields */} // ContextKeyClientID is the integer ID of the authenticated oauth_clients // row, populated by BearerTokenHandler after successful token validation. ContextKeyClientID = contextKey{/* contains filtered or unexported fields */} // ContextKeyClientName is the human-readable name of the authenticated // oauth_clients row (oauth_clients.name), populated by BearerTokenHandler // after successful token validation. Consumers use this for per-client // audit logging, multi-tenant routing, or vendor attribution on outbound // calls. ContextKeyClientName = contextKey{/* contains filtered or unexported fields */} )
var ( ErrInvalidRequest = errors.New("invalid_request") ErrAccessDenied = errors.New("access_denied") ErrUnsupportedResponseType = errors.New("unsupported_response_type") ErrInvalidScope = errors.New("invalid_scope") ErrServerError = errors.New("server_error") ErrInvalidClient = errors.New("invalid_client") ErrInvalidGrant = errors.New("invalid_grant") ErrUnsupportedGrantType = errors.New("unsupported_grant_type") ErrCodeChallengeRequired = errors.New("invalid_request") ErrUnsupportedCodeChallengeMethod = errors.New("invalid_request") ErrInvalidCodeChallengeLen = errors.New("invalid_request") ErrInvalidCodeChallenge = errors.New("invalid code challenge") ErrExpiredRefreshToken = errors.New("expired refresh token") ErrInvalidRefreshToken = errors.New("invalid refresh token") ErrInvalidRedirectURI = errors.New("invalid redirect uri") )
OAuth2 error types per RFC 6749 Section 5.2. Use these with NewErrorResponse to create properly formatted error responses.
Example:
if client == nil {
return nil, NewErrorResponse(ErrInvalidClient)
}
var DB up.Session
DB is the database session used for OAuth2 operations.
var Descriptions = map[error]string{ ErrInvalidRequest: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.", ErrUnauthorizedClient: "The client is not authorized to request an authorization code using this method.", ErrAccessDenied: "The resource owner or authorization server denied the request.", ErrUnsupportedResponseType: "The authorization server does not support obtaining an authorization code using this method.", ErrInvalidScope: "The requested scope is invalid, unknown, or malformed.", ErrServerError: "The authorization server encountered an unexpected condition that prevented it from fulfilling the request.", ErrTemporarilyUnavailable: "The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.", ErrInvalidClient: "Client authentication failed.", ErrInvalidGrant: "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.", ErrUnsupportedGrantType: "The authorization grant type is not supported by the authorization server.", ErrCodeChallengeRequired: "PKCE is required. code_challenge is missing.", ErrUnsupportedCodeChallengeMethod: "Selected code_challenge_method not supported.", ErrInvalidCodeChallengeLen: "Code challenge length must be between 43 and 128 characters.", ErrInvalidRedirectURI: "The redirect URI provided is not a valid URI.", }
descriptions are base on https://github.com/go-oauth2/oauth2/blob/master/errors/response.go and follow RFC 6749
var StatusCodes = map[error]int{ ErrInvalidRequest: 400, ErrUnauthorizedClient: 401, ErrAccessDenied: 403, ErrUnsupportedResponseType: 401, ErrInvalidScope: 400, ErrServerError: 500, ErrTemporarilyUnavailable: 503, ErrInvalidClient: 401, ErrInvalidGrant: 400, ErrUnsupportedGrantType: 400, ErrCodeChallengeRequired: 400, ErrUnsupportedCodeChallengeMethod: 400, ErrInvalidCodeChallengeLen: 400, ErrInvalidCodeChallenge: 401, ErrInvalidRefreshToken: 401, ErrExpiredRefreshToken: 401, ErrInvalidRedirectURI: 400, }
status codes are based on https://github.com/go-oauth2/oauth2/blob/master/errors/response.go and follow RFC 6749
Functions ¶
func BearerTokenHandler ¶
func BearerTokenHandler(unguardedRoute []string, GuardedRouteGroups []string, ErrorLogger *log.Logger, o *Service) func(next http.Handler) http.Handler
authenticate the bearer token attached to a HTTP request is a valid token by getting it by the plain text value from the db and checking that is not expired. Valid tokens are added to the context of the request as an access token for use by other middleware deeper in the stack. The middleware is designed for use in the global stack, so it is going to get loaded on every request, as a result the the guarded route groups are first checked and quickly passed to the next middleware if the path is not in a guarded group.
func ChallengeCodeValidate ¶
ChallengeCodeValidate validates a PKCE code challenge and method per RFC 7636. The challenge method must be "S256" and the code must be 43-128 characters.
Example:
ok, err := ChallengeCodeValidate("abc123...xyz", "S256")
if err != nil {
return nil, NewErrorResponse(err)
}
Validation rules:
- method must be "S256" (plain is not supported)
- challengeCode must not be empty
- challengeCode length must be between 43 and 128 characters
func GenerateTokenExpiry ¶
GenerateTokenExpiry creates a token expiry time for use with any type of tokens issued by the authorization server. Currently returns 24 hours from now in UTC.
Example:
expiry := facades.GenerateTokenExpiry(24) token.Expires = expiry
func IsExpired ¶
func IsExpired(token interface{}) bool
IsExpired checks if the provided token has expired by comparing its 'Expires' field with the current UTC time. Returns true if still valid, false if expired. Works with any struct that has an Expires field of type time.Time.
Example:
token := &OauthToken{Expires: time.Now().Add(-1 * time.Hour)} // expired
if !IsExpired(token) {
fmt.Println("Token has expired")
}
func ScopeHandler ¶
func ScopeHandler(UnguardedRoutes []string, GuardedRouteGroups []string, ErrorLogger *log.Logger, o *Service) func(next http.Handler) http.Handler
look up the scopes assigned to the current route and confirm the access token passed in the http request has the same scopes assigned to the token.
Types ¶
type AuthorizationResponse ¶
type AuthorizationResponse struct {
GrantType string `json:"-"`
TokenType string `json:"token_type"`
Code string `json:"code"`
State string `json:"state"`
RedirectUri RedirectUri `json:"redirectURL"`
CSRFToken string `json:"-"`
}
AuthorizationResponse represents the response from an authorization request. Used in authorization code and PKCE flows.
Example:
response := &AuthorizationResponse{
Code: "auth_code_123",
State: "xyz",
TokenType: "code",
}
type AuthorizationToken ¶
type AuthorizationToken struct {
ID int `db:"id,omitempty" json:"id"`
UserID *int `db:"user_id,omitempty" json:"user_id"`
ClientID int `db:"client_id" json:"client_id"`
PlainText string `db:"-" json:"token"`
Hash []byte `db:"token_hash" json:"-"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
Expires time.Time `db:"expiry" json:"expiry"`
ChallengeCode string `db:"challenge_code,omitempty" json:"ChallengeCode"`
ChallengeCodeMethod string `db:"challenge_code_method,omitempty" json:"ChallengeCodeMethod"`
State string `db:"-" json:"state"`
}
type Client ¶
type Client struct {
ID int `db:"id,omitempty" json:"id"`
UserID *int `db:"user_id,omitempty" json:"user_id"`
Secret string `db:"secret" json:"secret"`
PlainText string `db:"-" json:"-"`
Name string `db:"name"`
Revoked int `db:"revoked"`
Type string `db:"type"`
Flow string `db:"flow" json:"flow"`
RedirectUrl string `db:"redirect_url,omitempty" json:"redirectURL"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
Client represents an OAuth2 client application registered with the server. Type contains the RFC 6749 grant type: "authorization_code", "client_credentials", or "password". Flow discriminates authorization_code sub-flows: "plain", "pkce", or "pkce_implicit".
Example:
client := &Client{
Name: "My App",
Secret: "client_secret_here",
Type: "client_credentials",
RedirectUrl: "https://myapp.com/callback",
}
type Configuration ¶
type Configuration struct {
PkceImplicitAuthorizationScopes map[string]string `yaml:"PkceImplicitAuthorizationScopes"` // scopes that the authorization server may assign to a pkce implicit authorization code request
Scopes Scopes `yaml:"Scopes"` // scopes that the authorization server may assign to a oauth token request
UnguardedRoutes []string `yaml:"UnguardedRoutes"` // paths that do not require authentication (relative paths may not omit leading slash)
GuardedRouteGroups []string `yaml:"GuardedRouteGroups"` // paths that require authentication (relative paths may omit leading slash)
AuthorizationTokenTTL time.Duration `yaml:"AuthorizationTokenTTL"` // duration the authorization token is valid (default: 60 minutes)
OauthTokenTTL time.Duration `yaml:"OauthTokenTTL"` // duration a token is valid (default: 24 hours)
PkceImplicitTTL time.Duration `yaml:"PkceImplicitTTL"` // duration a PKCE implicit token is valid (default: 300 seconds)
RefreshTokenTokenTTL time.Duration `yaml:"RefreshTokenTokenTTL"` // duration a refresh token is valid (default: 24 hours)
VerifyTemplatePath string `yaml:"VerifyTemplatePath"` // the path to the verify view template relative to the resources dir
}
Configuration holds the OAuth2 server configuration loaded from oauth.yml.
Example (oauth.yml):
Scopes: read: "Read access" write: "Write access" UnguardedRoutes: - /oauth/token - /health OauthTokenTTL: 24 RefreshTokenTokenTTL: 168
type ErrorResponse ¶
type ErrorResponse struct {
Description string `json:"error_description"`
Error string `json:"error"`
ErrorCode int `json:"-"`
URI string `json:"error_uri,omitempty"`
}
ErrorResponse represents an OAuth2 error response per RFC 6749.
Example:
err := NewErrorResponse(ErrInvalidClient)
// Returns:
// {
// "error": "invalid_client",
// "error_description": "Client authentication failed."
// }
func NewErrorResponse ¶
func NewErrorResponse(err error) *ErrorResponse
NewErrorResponse creates an ErrorResponse from an error type. Maps the error to its RFC 6749 description and HTTP status code.
Example:
err := NewErrorResponse(ErrInvalidClient) // err.Error = "invalid_client" // err.Description = "Client authentication failed." // err.ErrorCode = 401 // Use with JSON response: w.WriteHeader(err.ErrorCode) json.NewEncoder(w).Encode(err)
Note: ErrorCode is used for HTTP status only and is not included in the JSON response. The JSON output uses error_description (Description) and error_uri (URI) per RFC 6749.
type OauthResponse ¶
type OauthResponse struct {
GrantType string `json:"-"`
TokenType string `json:"token_type"`
ExpiresIn int64 `json:"expires_in"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token,omitempty"`
Scope string `json:"scope,omitempty"`
}
OauthResponse represents the response from a token exchange request. Contains the access token and optionally a refresh token.
Example:
// Response JSON:
// {
// "token_type": "Bearer",
// "access_token": "eyJhbGciOiJIUzI1NiIs...",
// "refresh_token": "refresh_abc123",
// "expires_in": 3600
// }
type OauthToken ¶
type OauthToken struct {
ID int `db:"id,omitempty" json:"id"`
UserID *int `db:"user_id,omitempty" json:"user_id"`
ClientID int `db:"client_id" json:"client_id"`
PlainText string `db:"-" json:"token"`
Hash []byte `db:"token_hash" json:"-"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
Expires time.Time `db:"expiry" json:"expiry"`
RefreshToken string `db:"-" json:"refresh_token"`
Scopes string `db:"scopes,omitempty" json:"scopes"`
}
type RedirectUri ¶
type RefreshToken ¶
type RefreshToken struct {
ID int `db:"id,omitempty" json:"id"`
AccessTokenID int `db:"access_token_id" json:"-"`
Expires time.Time `db:"expiry" json:"expiry"`
Hash []byte `db:"token_hash" json:"-"`
PlainText string `db:"-" json:"token"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
}
type Scopes ¶
Scopes represents a map of scope names to their descriptions.
Example:
scopes := Scopes{
"read": "Read access to resources",
"write": "Write access to resources",
}
type Service ¶
type Service struct {
//Auth *auth.Auth
DB *database.Database
GrantTypes map[string]string
Config Configuration
ErrorLog *log.Logger
Renderer *render.Render
Session *scs.SessionManager
Mux *mux.Mux
}
Service provides the core OAuth2 functionality including token generation, validation, and client management.
Example:
facades := facades.New(adeleApp) token, err := facades.GenerateOauthToken()
func New ¶
New creates a new Service instance with the given Adele application. It initializes the database session and loads configuration from config/oauth.yml.
Example:
svc, err := api.New(adeleApp)
if err != nil {
return err
}
func NewWithConfig ¶
func NewWithConfig(a *adele.Adele, config Configuration) (Service, error)
NewWithConfig creates a new Service instance with a custom configuration. Used primarily for testing.
Example:
cfg := api.Configuration{Scopes: map[string]string{"read": "Read access"}}
svc, err := api.NewWithConfig(adeleApp, cfg)
if err != nil {
return err
}
func (*Service) AccessTokenGrantExchange ¶
func (o *Service) AccessTokenGrantExchange(w http.ResponseWriter, r *http.Request) (*OauthResponse, *ErrorResponse)
AccessTokenGrantExchange exchanges credentials for an access token. Supports client_credentials, password, and authorization_code (PKCE code exchange) grant types.
Example (client_credentials):
// POST /oauth/token // Content-Type: application/x-www-form-urlencoded // client_id=1&client_secret=secret&grant_type=client_credentials&scopes=read
Example (PKCE code exchange):
// POST /oauth/token // client_id=1&code=auth_code&code_verifier=verifier& // code_challenge_method=S256&grant_type=authorization_code&scopes=read response, err := facades.AccessTokenGrantExchange(w, r) // response.AccessToken contains the bearer token // response.RefreshToken contains the refresh token (if applicable)
func (*Service) AuthenticateToken ¶
token authentication attached to a http request in the form of bearer token.
func (*Service) AuthenticationCheckForScopes ¶
func (*Service) AuthenticationTokenMiddleware ¶
func (*Service) AuthorizationClientCodeExchange ¶
func (o *Service) AuthorizationClientCodeExchange(w http.ResponseWriter, r *http.Request, client *Client) (*AuthorizationResponse, *ErrorResponse)
func (*Service) AuthorizationClientCodeExchangeImplicit ¶
func (o *Service) AuthorizationClientCodeExchangeImplicit(w http.ResponseWriter, r *http.Request, client *Client) (*AuthorizationResponse, *ErrorResponse)
func (*Service) AuthorizationClientExchange ¶
func (o *Service) AuthorizationClientExchange(w http.ResponseWriter, r *http.Request, client *Client) (*AuthorizationResponse, *ErrorResponse)
func (*Service) AuthorizationGrantExchange ¶
func (o *Service) AuthorizationGrantExchange(w http.ResponseWriter, r *http.Request) (*AuthorizationResponse, *ErrorResponse)
AuthorizationGrantExchange validates an authorization request and returns the redirect URI. This is the first step in the authorization code flow (GET request).
Required form fields: client_id, grant_type, response_type, redirect_uri, state, code_challenge, code_challenge_method, scopes
REQUIREMENT: This handler stores intermediate OAuth state (CSRF token, and on the POST counterpart user_id and the in-flight authorization code / PKCE challenge) in the user session via o.Session.Put. The request MUST be served through the framework's session.LoadAndSave middleware (auto-mounted around every route registered on a.Routes) so that scs has session data wired into r.Context(). Invoking this handler directly with a request whose context has not been hydrated by LoadAndSave will panic ("scs: no session data in context"). Tests that exercise this handler must call o.Session.Load on the request context (see oauth_test.go) or wrap the handler in o.Session.LoadAndSave before serving.
Example:
// GET /oauth/authorize?client_id=1&grant_type=authorization_code&response_type=code&
// redirect_uri=https://app.com/callback&state=xyz&code_challenge=abc&
// code_challenge_method=S256&scopes=read%20write
response, err := facades.AuthorizationGrantExchange(w, r)
if err != nil {
// Handle error
}
// Redirect to response.RedirectUri.URI
func (*Service) AuthorizationGrantExchangePost ¶
func (o *Service) AuthorizationGrantExchangePost(w http.ResponseWriter, r *http.Request) (*AuthorizationResponse, *ErrorResponse)
AuthorizationGrantExchangePost processes the authorization form submission. Handles plain, pkce, and pkce_implicit authorization code flows.
Example:
// POST /oauth/authorize
// Content-Type: application/x-www-form-urlencoded
// client_id=1&grant_type=authorization_code&response_type=code&...
response, err := facades.AuthorizationGrantExchangePost(w, r)
if err != nil {
// Handle error
}
// For PKCE: redirect to response.RedirectUri.URI with code
// For implicit: return response with token
func (*Service) CheckUserPasswordMatches ¶
func (*Service) ConsumeAuthorizationToken ¶
func (o *Service) ConsumeAuthorizationToken(plainText string) (*AuthorizationToken, error)
ConsumeAuthorizationToken atomically retrieves and deletes an authorization token. Returns the token if found and deleted, nil if already consumed or not found.
func (*Service) DeleteAuthorizationToken ¶
delete a authorization token by id from the database and return an error if necessary
func (*Service) DeleteOauthToken ¶
func (*Service) DeleteRefreshTokenByToken ¶
Delete a refresh token from db by deriving its hash from the plain text token.
func (*Service) GenerateAuthorizationToken ¶
func (o *Service) GenerateAuthorizationToken() (*AuthorizationToken, error)
Create a new authorization token
func (*Service) GenerateOauthToken ¶
func (o *Service) GenerateOauthToken() (*OauthToken, error)
Create a oauth token that is always the same length each time one is generated.
func (*Service) GenerateRefreshToken ¶
func (o *Service) GenerateRefreshToken(userID int, AccessTokenID int, clientID int) (*RefreshToken, error)
Generate a string representing the authorization granted to the client by the resource owner. The string is usually opaque to the client. The token denotes an identifier used to retrieve the authorization information. https://datatracker.ietf.org/doc/html/rfc6749#section-1.5
func (*Service) GetAuthTokenFromHeader ¶
func (o *Service) GetAuthTokenFromHeader(r *http.Request) (*OauthToken, error)
extract a token from the http request header
func (*Service) GetAuthenticatedUser ¶
Get the current authenticated user
func (*Service) GetAuthorizationTokenByToken ¶
func (o *Service) GetAuthorizationTokenByToken(plainText string) (*AuthorizationToken, error)
Get a authorization token by hashing the plain text value and querying token_hash.
func (*Service) GetByToken ¶
func (o *Service) GetByToken(plainText string) (*OauthToken, error)
get the token from the db by hashing the plain text value and querying token_hash
func (*Service) GetClient ¶
Get the client by the ID and if no client is found the return value will be nil.
func (*Service) GetOauthToken ¶
func (o *Service) GetOauthToken(id int) (*OauthToken, error)
func (*Service) GetRefreshByToken ¶
func (o *Service) GetRefreshByToken(plainText string) (*RefreshToken, error)
Find a refresh token in the db by hashing the plain text value and querying token_hash.
func (*Service) InsertAuthorizationToken ¶
func (o *Service) InsertAuthorizationToken(token *AuthorizationToken) (*AuthorizationToken, error)
Add a authorization token to the database and return the token id in the response
func (*Service) InsertClient ¶
InsertClient hashes the client secret with bcrypt and persists the client to the database. The plaintext secret is available in the returned Client's PlainText field — it is shown to the caller once and never stored.
func (*Service) InsertOauthToken ¶
func (o *Service) InsertOauthToken(token *OauthToken) (*OauthToken, error)
Add a token to the db and return the token id in the response
func (*Service) InsertRefreshToken ¶
func (o *Service) InsertRefreshToken(token *RefreshToken) error
Add a authorization token to the db and return the token id in the response
func (*Service) RefreshTokenExchange ¶
func (o *Service) RefreshTokenExchange(w http.ResponseWriter, r *http.Request) (*OauthResponse, *ErrorResponse)
RefreshTokenExchange exchanges a valid refresh token for a new access token. Per RFC 6749, the new token's scopes must be a subset of the original token's scopes.
Required fields: client_id, client_secret, grant_type (must be "refresh_token"), refresh_token, scopes
Example:
// POST /oauth/token/refresh // Content-Type: application/x-www-form-urlencoded // client_id=1&client_secret=secret&grant_type=refresh_token& // refresh_token=abc123&scopes=read response, err := facades.RefreshTokenExchange(w, r) // response.AccessToken = new access token // response.RefreshToken = new refresh token
func (*Service) ResourceOwnerTokenExchange ¶
func (o *Service) ResourceOwnerTokenExchange(r *http.Request, w http.ResponseWriter, client Client) (*OauthToken, *RefreshToken, *ErrorResponse)
func (*Service) TokenIsExpired ¶
TokenIsExpired checks if the provided token has expired by comparing its 'Expires' field with the current UTC time. Returns true if the token is still valid (not expired), false if expired or if the token doesn't have an Expires field.
Example:
token := &OauthToken{Expires: time.Now().Add(1 * time.Hour)}
if facades.TokenIsExpired(token) {
fmt.Println("Token is still valid")
}
func (*Service) UserIsLoggedIn ¶
search for the suer in the session and return a bool if exists
func (*Service) ValidateClientRedirect ¶
Validate that a given uri can be used for redirection.
func (*Service) VerifyAuthorizationCode ¶
func (o *Service) VerifyAuthorizationCode(token AuthorizationToken, codeVerifier string) bool
Verify by calculating the code challenge from the received "code_verifier" and comparing it with the previously associated "code_challenge" after first transforming it according to the "code_challenge_method" method specified by the client. The formula for this is BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) == code_challenge, but we will need to replace the "=" for padding as it would be parsed by the URL in the browser and converted to a URL safe encoded character.
type User ¶
type User struct {
ID int `db:"id,omitempty"`
FirstName string `db:"first_name"`
LastName string `db:"last_name"`
Email string `db:"email"`
Active int `db:"user_active"`
Password string `db:"password"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
Token OauthToken `db:"-"`
}