README
¶
OSIN
Golang OAuth2 server library
OSIN is an OAuth2 server library for the Go language, as specified at http://tools.ietf.org/html/rfc6749 and http://tools.ietf.org/html/draft-ietf-oauth-v2-10.
Using it, you can build your own OAuth2 authentication service.
The library implements the majority of the specification, like authorization and token endpoints, and authorization code, implicit, resource owner and client credentials grant types.
Example Server
import "github.com/RangelReale/osin"
// TestStorage implements the "osin.Storage" interface
server := osin.NewServer(osin.NewServerConfig(), &TestStorage{})
// Authorization code endpoint
http.HandleFunc("/authorize", func(w http.ResponseWriter, r *http.Request) {
resp := server.NewResponse()
defer resp.Close()
if ar := server.HandleAuthorizeRequest(resp, r); ar != nil {
// HANDLE LOGIN PAGE HERE
ar.Authorized = true
server.FinishAuthorizeRequest(resp, r, ar)
}
osin.OutputJSON(resp, w, r)
})
// Access token endpoint
http.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
resp := server.NewResponse()
defer resp.Close()
if ar := server.HandleAccessRequest(resp, r); ar != nil {
ar.Authorized = true
server.FinishAccessRequest(resp, r, ar)
}
osin.OutputJSON(resp, w, r)
})
http.ListenAndServe(":14000", nil)
Example Access
Open in your web browser:
http://localhost:14000/authorize?response_type=code&client_id=1234&redirect_url=http%3A%2F%2Flocalhost%3A14000%2Fappauth%2Fcode
License
The code is licensed using "New BSD" license.
Author
Rangel Reale rangelreale@gmail.com
Changes
2014-06-25
- BREAKING CHANGES:
-
Storage interface has 2 new methods, Clone and Close, to better support storages that need to clone / close in each connection (mgo)
-
Client was changed to be an interface instead of an struct. Because of that, the Storage interface also had to change, as interface is already a pointer.
-
HOW TO FIX YOUR CODE:
-
In your Storage, add a Clone function returning itself, and a do nothing Close.
-
In your Storage, replace all *osin.Client with osin.Client (remove the pointer reference)
-
If you used the osin.Client struct directly in your code, change it to osin.DefaultClient, which is a struct with the same fields that implements the interface.
-
Change all accesses using osin.Client to use the methods instead of the fields directly.
-
You MUST defer Response.Close in all your http handlers, otherwise some Storages may not clean correctly.
resp := server.NewResponse() defer resp.Close()
-
-
Documentation
¶
Index ¶
- Constants
- func FirstUri(baseUriList string, separator string) string
- func OutputJSON(rs *Response, w http.ResponseWriter, r *http.Request) error
- func ValidateUri(baseUri string, redirectUri string) error
- func ValidateUriList(baseUriList string, redirectUri string, separator string) error
- type AccessData
- type AccessRequest
- type AccessRequestType
- type AccessTokenGen
- type AccessTokenGenDefault
- type AllowedAccessType
- type AllowedAuthorizeType
- type AuthorizeData
- type AuthorizeRequest
- type AuthorizeRequestType
- type AuthorizeTokenGen
- type AuthorizeTokenGenDefault
- type BasicAuth
- type BearerAuth
- type Client
- type DefaultClient
- type DefaultErrorId
- type DefaultErrors
- type InfoRequest
- type Response
- func (r *Response) Close()
- func (r *Response) GetRedirectUrl() (string, error)
- func (r *Response) SetError(id string, description string)
- func (r *Response) SetErrorState(id string, description string, state string)
- func (r *Response) SetErrorUri(id string, description string, uri string, state string)
- func (r *Response) SetRedirect(url string)
- func (r *Response) SetRedirectFragment(f bool)
- type ResponseData
- type ResponseType
- type Server
- func (s *Server) FinishAccessRequest(w *Response, r *http.Request, ar *AccessRequest)
- func (s *Server) FinishAuthorizeRequest(w *Response, r *http.Request, ar *AuthorizeRequest)
- func (s *Server) FinishInfoRequest(w *Response, r *http.Request, ir *InfoRequest)
- func (s *Server) HandleAccessRequest(w *Response, r *http.Request) *AccessRequest
- func (s *Server) HandleAuthorizeRequest(w *Response, r *http.Request) *AuthorizeRequest
- func (s *Server) HandleInfoRequest(w *Response, r *http.Request) *InfoRequest
- func (s *Server) NewResponse() *Response
- type ServerConfig
- type Storage
- type UriValidationError
Constants ¶
const ( E_INVALID_REQUEST string = "invalid_request" E_UNAUTHORIZED_CLIENT = "unauthorized_client" E_ACCESS_DENIED = "access_denied" E_UNSUPPORTED_RESPONSE_TYPE = "unsupported_response_type" E_INVALID_SCOPE = "invalid_scope" E_SERVER_ERROR = "server_error" E_TEMPORARILY_UNAVAILABLE = "temporarily_unavailable" E_UNSUPPORTED_GRANT_TYPE = "unsupported_grant_type" E_INVALID_GRANT = "invalid_grant" E_TOKEN_EXPIRE = "token_expire" E_INVALID_CLIENT = "invalid_client" )
Variables ¶
This section is empty.
Functions ¶
func OutputJSON ¶
OutputJSON encodes the Response to JSON and writes to the http.ResponseWriter
func ValidateUri ¶
ValidateUri validates that redirectUri is contained in baseUri
Types ¶
type AccessData ¶
type AccessData struct { // Client information Client Client // Authorize data, for authorization code AuthorizeData *AuthorizeData // Previous access data, for refresh token AccessData *AccessData // Access token AccessToken string // Refresh Token. Can be blank RefreshToken string // Token expiration in seconds ExpiresIn int32 RefreshExpirationIn int32 // Requested scope Scope string // Redirect Uri from request RedirectUri string // Date created CreatedAt time.Time // Data to be passed to storage. Not used by the library. UserData interface{} }
AccessData represents an access grant (tokens, expiration, client, etc)
func (*AccessData) ExpireAt ¶
func (d *AccessData) ExpireAt() time.Time
ExpireAt returns the expiration date
func (*AccessData) IsExpired ¶
func (d *AccessData) IsExpired() bool
IsExpired returns true if access expired
func (*AccessData) IsExpiredAt ¶
func (d *AccessData) IsExpiredAt(t time.Time) bool
IsExpiredAt returns true if access expires at time 't'
type AccessRequest ¶
type AccessRequest struct { Type AccessRequestType Code string Client Client AuthorizeData *AuthorizeData AccessData *AccessData // Force finish to use this access data, to allow access data reuse ForceAccessData *AccessData RedirectUri string Scope string Username string Password string Wxcode string AssertionType string Assertion string Captcha string Otp string // Set if request is authorized Authorized bool // Token expiration in seconds. Change if different from default Expiration int32 RefreshExpiration int32 // Set if a refresh token should be generated GenerateRefresh bool // Data to be passed to storage. Not used by the library. UserData interface{} // HttpRequest *http.Request for special use HttpRequest *http.Request }
AccessRequest is a request for access tokens
type AccessRequestType ¶
type AccessRequestType string
AccessRequestType is the type for OAuth param `grant_type`
const ( AUTHORIZATION_CODE AccessRequestType = "authorization_code" REFRESH_TOKEN AccessRequestType = "refresh_token" PASSWORD AccessRequestType = "password" CLIENT_CREDENTIALS AccessRequestType = "client_credentials" ASSERTION AccessRequestType = "assertion" IMPLICIT AccessRequestType = "__implicit" CAPTCHA AccessRequestType = "captcha" WX AccessRequestType = "wx" )
type AccessTokenGen ¶
type AccessTokenGen interface {
GenerateAccessToken(data *AccessData, generaterefresh bool) (accesstoken string, refreshtoken string, err error)
}
AccessTokenGen generates access tokens
type AccessTokenGenDefault ¶
type AccessTokenGenDefault struct { }
AccessTokenGenDefault is the default authorization token generator
func (*AccessTokenGenDefault) GenerateAccessToken ¶
func (a *AccessTokenGenDefault) GenerateAccessToken(data *AccessData, generaterefresh bool) (accesstoken string, refreshtoken string, err error)
GenerateAccessToken generates base64-encoded UUID access and refresh tokens
type AllowedAccessType ¶
type AllowedAccessType []AccessRequestType
AllowedAccessType is a collection of allowed access request types
func (AllowedAccessType) Exists ¶
func (t AllowedAccessType) Exists(rt AccessRequestType) bool
Exists returns true if the access type exists in the list
type AllowedAuthorizeType ¶
type AllowedAuthorizeType []AuthorizeRequestType
AllowedAuthorizeType is a collection of allowed auth request types
func (AllowedAuthorizeType) Exists ¶
func (t AllowedAuthorizeType) Exists(rt AuthorizeRequestType) bool
Exists returns true if the auth type exists in the list
type AuthorizeData ¶
type AuthorizeData struct { // Client information Client Client // Authorization code Code string // Token expiration in seconds ExpiresIn int32 // Requested scope Scope string // Redirect Uri from request RedirectUri string // State data from request State string // Date created CreatedAt time.Time // Data to be passed to storage. Not used by the library. UserData interface{} }
Authorization data
func (*AuthorizeData) ExpireAt ¶
func (d *AuthorizeData) ExpireAt() time.Time
ExpireAt returns the expiration date
func (*AuthorizeData) IsExpired ¶
func (d *AuthorizeData) IsExpired() bool
IsExpired is true if authorization expired
func (*AuthorizeData) IsExpiredAt ¶
func (d *AuthorizeData) IsExpiredAt(t time.Time) bool
IsExpired is true if authorization expires at time 't'
type AuthorizeRequest ¶
type AuthorizeRequest struct { Type AuthorizeRequestType Client Client Scope string RedirectUri string State string // Set if request is authorized Authorized bool // Token expiration in seconds. Change if different from default. // If type = TOKEN, this expiration will be for the ACCESS token. Expiration int32 // Data to be passed to storage. Not used by the library. UserData interface{} // HttpRequest *http.Request for special use HttpRequest *http.Request }
Authorize request information
type AuthorizeRequestType ¶
type AuthorizeRequestType string
AuthorizeRequestType is the type for OAuth param `response_type`
const ( CODE AuthorizeRequestType = "code" TOKEN AuthorizeRequestType = "token" )
type AuthorizeTokenGen ¶
type AuthorizeTokenGen interface {
GenerateAuthorizeToken(data *AuthorizeData) (string, error)
}
AuthorizeTokenGen is the token generator interface
type AuthorizeTokenGenDefault ¶
type AuthorizeTokenGenDefault struct { }
AuthorizeTokenGenDefault is the default authorization token generator
func (*AuthorizeTokenGenDefault) GenerateAuthorizeToken ¶
func (a *AuthorizeTokenGenDefault) GenerateAuthorizeToken(data *AuthorizeData) (ret string, err error)
GenerateAuthorizeToken generates a base64-encoded UUID code
type BearerAuth ¶
type BearerAuth struct {
Code string
}
Parse bearer authentication header
func CheckBearerAuth ¶
func CheckBearerAuth(r *http.Request) *BearerAuth
Return "Bearer" token from request. The header has precedence over query string.
type Client ¶
type Client interface { // Client id GetId() string // Client secret GetSecret() string // Base client uri GetRedirectUri() string // Data to be passed to storage. Not used by the library. GetUserData() interface{} }
Client information
type DefaultClient ¶
DefaultClient stores all data in struct variables
func (*DefaultClient) CopyFrom ¶
func (d *DefaultClient) CopyFrom(client Client)
func (*DefaultClient) GetId ¶
func (d *DefaultClient) GetId() string
func (*DefaultClient) GetRedirectUri ¶
func (d *DefaultClient) GetRedirectUri() string
func (*DefaultClient) GetSecret ¶
func (d *DefaultClient) GetSecret() string
func (*DefaultClient) GetUserData ¶
func (d *DefaultClient) GetUserData() interface{}
type DefaultErrorId ¶
type DefaultErrorId string
type DefaultErrors ¶
type DefaultErrors struct {
// contains filtered or unexported fields
}
Default errors and messages
func NewDefaultErrors ¶
func NewDefaultErrors() *DefaultErrors
NewDefaultErrors initializes OAuth2 error codes and descriptions. http://tools.ietf.org/html/rfc6749#section-4.1.2.1 http://tools.ietf.org/html/rfc6749#section-4.2.2.1 http://tools.ietf.org/html/rfc6749#section-5.2 http://tools.ietf.org/html/rfc6749#section-7.2
func (*DefaultErrors) Get ¶
func (e *DefaultErrors) Get(id string) string
type InfoRequest ¶
type InfoRequest struct { Code string // Code to look up AccessData *AccessData // AccessData associated with Code }
InfoRequest is a request for information about some AccessData
type Response ¶
type Response struct { Type ResponseType StatusCode int StatusText string ErrorStatusCode int URL string Output ResponseData Headers http.Header IsError bool ErrorId string InternalError error RedirectInFragment bool // Storage to use in this response - required Storage Storage }
Server response
func NewResponse ¶
func (*Response) GetRedirectUrl ¶
GetRedirectUrl returns the redirect url with all query string parameters
func (*Response) SetError ¶
SetError sets an error id and description on the Response state and uri are left blank
func (*Response) SetErrorState ¶
SetErrorState sets an error id, description, and state on the Response uri is left blank
func (*Response) SetErrorUri ¶
SetErrorUri sets an error id, description, state, and uri on the Response
func (*Response) SetRedirect ¶
SetErrorUri changes the response to redirect to the given url
func (*Response) SetRedirectFragment ¶
SetRedirectFragment sets redirect values to be passed in fragment instead of as query parameters
type ResponseType ¶
type ResponseType int
Response type enum
const ( DATA ResponseType = iota REDIRECT )
type Server ¶
type Server struct { Config *ServerConfig Storage Storage AuthorizeTokenGen AuthorizeTokenGen AccessTokenGen AccessTokenGen Now func() time.Time }
Server is an OAuth2 implementation
func NewServer ¶
func NewServer(config *ServerConfig, storage Storage) *Server
NewServer creates a new server instance
func (*Server) FinishAccessRequest ¶
func (s *Server) FinishAccessRequest(w *Response, r *http.Request, ar *AccessRequest)
func (*Server) FinishAuthorizeRequest ¶
func (s *Server) FinishAuthorizeRequest(w *Response, r *http.Request, ar *AuthorizeRequest)
func (*Server) FinishInfoRequest ¶
func (s *Server) FinishInfoRequest(w *Response, r *http.Request, ir *InfoRequest)
FinishInfoRequest finalizes the request handled by HandleInfoRequest
func (*Server) HandleAccessRequest ¶
func (s *Server) HandleAccessRequest(w *Response, r *http.Request) *AccessRequest
HandleAccessRequest is the http.HandlerFunc for handling access token requests
func (*Server) HandleAuthorizeRequest ¶
func (s *Server) HandleAuthorizeRequest(w *Response, r *http.Request) *AuthorizeRequest
HandleAuthorizeRequest is the main http.HandlerFunc for handling authorization requests
func (*Server) HandleInfoRequest ¶
func (s *Server) HandleInfoRequest(w *Response, r *http.Request) *InfoRequest
HandleInfoRequest is an http.HandlerFunc for server information NOT an RFC specification.
func (*Server) NewResponse ¶
NewResponse creates a new response for the server
type ServerConfig ¶
type ServerConfig struct { // Authorization token expiration in seconds (default 5 minutes) AuthorizationExpiration int32 // Access token expiration in seconds (default 1 hour) AccessExpiration int32 // Token type to return TokenType string // List of allowed authorize types (only CODE by default) AllowedAuthorizeTypes AllowedAuthorizeType // List of allowed access types (only AUTHORIZATION_CODE by default) AllowedAccessTypes AllowedAccessType // HTTP status code to return for errors - default 200 // Only used if response was created from server ErrorStatusCode int // If true allows client secret also in params, else only in // Authorization header - default false AllowClientSecretInParams bool // If true allows access request using GET, else only POST - default false AllowGetAccessRequest bool // Separator to support multiple URIs in Client.GetRedirectUri(). // If blank (the default), don't allow multiple URIs. RedirectUriSeparator string }
ServerConfig contains server configuration information
func NewServerConfig ¶
func NewServerConfig() *ServerConfig
NewServerConfig returns a new ServerConfig with default configuration
type Storage ¶
type Storage interface { // Clone the storage if needed. For example, using mgo, you can clone the session with session.Clone // to avoid concurrent access problems. // This is to avoid cloning the connection at each method access. // Can return itself if not a problem. Clone() Storage // Close the resources the Storage potentially holds (using Clone for example) Close() // GetClient loads the client by id (client_id) GetClient(id string) (Client, error) // SaveAuthorize saves authorize data. SaveAuthorize(*AuthorizeData) error // LoadAuthorize looks up AuthorizeData by a code. // Client information MUST be loaded together. // Optionally can return error if expired. LoadAuthorize(code string) (*AuthorizeData, error) // RemoveAuthorize revokes or deletes the authorization code. RemoveAuthorize(code string) error // SaveAccess writes AccessData. // If RefreshToken is not blank, it must save in a way that can be loaded using LoadRefresh. SaveAccess(*AccessData) error // LoadAccess retrieves access data by token. Client information MUST be loaded together. // AuthorizeData and AccessData DON'T NEED to be loaded if not easily available. // Optionally can return error if expired. LoadAccess(token string) (*AccessData, error) // RemoveAccess revokes or deletes an AccessData. RemoveAccess(token string) error // LoadRefresh retrieves refresh AccessData. Client information MUST be loaded together. // AuthorizeData and AccessData DON'T NEED to be loaded if not easily available. // Optionally can return error if expired. LoadRefresh(token string) (*AccessData, error) // RemoveRefresh revokes or deletes refresh AccessData. RemoveRefresh(token string) error }
Storage interface
type UriValidationError ¶
type UriValidationError string
error returned when validation don't match
func (UriValidationError) Error ¶
func (e UriValidationError) Error() string