oidc

package module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 24, 2019 License: Apache-2.0 Imports: 19 Imported by: 2

README

oidc

Build Status Go Report Card

Golang Open ID Connect (OIDC) client library.

This library provides OIDC client that mimics standard oauth2 library and gives functionality for communicating with any OIDC-compliant provider.

This package was also inspired by go-oidc package by CoreOS.

Usage:

Directly oidc package:
package main

import (
    "context"
    
    "github.com/bwplotka/oidc"
)

func main() {
    // Performs call discovery endpoint to get all the details about provider.
    client, err := oidc.NewClient(context.Background(), "https://issuer-oidc.org")
    if err != nil {
        // handle err
    }
    
    extraDiscoveryStuff := map[string]interface{}{}
    err = client.Claims(&extraDiscoveryStuff)
    if err != nil {
        // handler err
    }
    
    // For exchanging code into token...
    client.Exchange(...)
    // For revoking tokens...
    client.Revoke(...)
    // For OIDC UserInfo...
    client.UserInfo(...)
    // For IDToken verification...
    client.Verifier(...)
    // For ID token refreshing...
    client.TokenSource(...).OIDCToken(context.Background())
}
Using login package for full oidc-browser-dance:

See login

Deps:

Vendoring using submodules. See .gitmodules

Wishlist:

  • Support 0 port (not pin into exact port)
  • Consider moving to structure logger with levels e.g logrus or just drop logging. (I don't like passing std logger in constructor)

Copyright 2017 Bartłomiej Płotka. All Rights Reserved. See LICENSE for licensing terms.

Documentation

Index

Constants

View Source
const (
	// ScopeOpenID is the mandatory scope for all OpenID Connect OAuth2 requests.
	ScopeOpenID        = "openid"
	ScopeOfflineAccess = "offline_access"
	ScopeEmail         = "email"
	ScopeProfile       = "profile"

	GrantTypeAuthCode     = "authorization_code"
	GrantTypeRefreshToken = "refresh_token"
	// GrantTypeServiceAccount is a custom ServiceAccount to support exchanging SA for ID token.
	GrantTypeServiceAccount = "service_account"

	ResponseTypeCode    = "code"     // Authorization Code flow
	ResponseTypeToken   = "token"    // Implicit flow for frontend apps.
	ResponseTypeIDToken = "id_token" // ID Token in url fragment

	DiscoveryEndpoint = "/.well-known/openid-configuration"
)

Variables

View Source
var DefaultKeySetExpiration = 30 * time.Second

DefaultKeySetExpiration specifies the time after which keys are expired and we need to refetch them.

View Source
var HTTPClientCtxKey struct{}

HTTPClientCtxKey is Context key which is used to fetch custom HTTP.Client. Used to pass special HTTP client (e.g with non-default timeout) or for tests.

Functions

This section is empty.

Types

type Audience

type Audience []string

func (*Audience) UnmarshalJSON

func (a *Audience) UnmarshalJSON(b []byte) error

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client represents an OpenID Connect client.

func NewClient

func NewClient(ctx context.Context, issuer string) (*Client, error)

NewClient uses the OpenID Connect discovery mechanism to construct a Client.

func (*Client) AuthCodeURL

func (c *Client) AuthCodeURL(cfg Config, state string, extra ...url.Values) string

AuthCodeURL returns a URL to OIDC provider's consent page that asks for permissions for the required scopes explicitly. State is a token to protect the user from CSRF attacks. You must always provide a non-zero string and validate that it matches the the state query parameter on your redirect callback. See http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest for more info.

func (*Client) Claims

func (c *Client) Claims(v interface{}) error

Claims unmarshals raw fields returned by the server during discovery.

var claims struct {
    ScopesSupported []string `json:"scopes_supported"`
    ClaimsSupported []string `json:"claims_supported"`
}

if err := client.Claims(&claims); err != nil {
    // handle unmarshaling error
}

For a list of fields defined by the OpenID Connect spec see: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata

func (*Client) Discovery

func (c *Client) Discovery() DiscoveryJSON

Discovery returns standard discovery fields held by OIDC provider we point to.

func (*Client) Exchange

func (c *Client) Exchange(ctx context.Context, cfg Config, code string, extra ...url.Values) (*Token, error)

Exchange converts an authorization code into a token.

It is used after a resource provider redirects the user back to the Redirect URI (the URL obtained from AuthCodeURL).

func (*Client) ExchangeServiceAccount

func (c *Client) ExchangeServiceAccount(ctx context.Context, cfg Config, googleServiceAccountJSON string, extra ...url.Values) (*Token, error)

Exchange converts an google service account JSON into a token. This is custom Corp Auth additional grant and is not in standard OpenID Connect flow.

func (*Client) Revoke

func (c *Client) Revoke(ctx context.Context, cfg Config, token string) error

Revoke revokes provided token. It can be access token or refresh token. In most, revoking access token will revoke refresh token which can be convenient. (IsValid e.g for Google OIDC).

func (*Client) TokenSource

func (c *Client) TokenSource(cfg Config, t *Token) TokenSource

TokenSource returns a TokenSource that returns t until t expires, automatically refreshing it as necessary using the provided context.

func (*Client) UserInfo

func (c *Client) UserInfo(ctx context.Context, tokenSource TokenSource) (*UserInfo, error)

UserInfo uses the token source to query the provider's user info endpoint.

func (*Client) Verifier

func (c *Client) Verifier(cfg VerificationConfig) *IDTokenVerifier

Verifier returns an IDTokenVerifier that uses the provider's key set to verify JWTs.

The returned IDTokenVerifier is tied to the Client's context and its behavior is undefined once the Client's context is canceled.

type Config

type Config struct {
	ClientID     string
	ClientSecret string
	RedirectURL  string
	Scopes       []string
}

Config is client configuration that contains all required client details to communicate with OIDC server.

type DiscoveryJSON

type DiscoveryJSON struct {
	Issuer        string `json:"issuer"`
	AuthURL       string `json:"authorization_endpoint"`
	TokenURL      string `json:"token_endpoint"`
	JWKSURL       string `json:"jwks_uri"`
	UserInfoURL   string `json:"userinfo_endpoint"`
	RevocationURL string `json:"revocation_endpoint"`
}

DiscoveryJSON is structure expected by Discovery endpoint.

type IDToken

type IDToken struct {
	// The URL of the server which issued this token. OpenID Connect
	// requires this value always be identical to the URL used for
	// initial discovery.
	//
	// Note: Because of a known issue with Google Accounts' implementation
	// this value may differ when using Google.
	//
	// See: https://developers.google.com/identity/protocols/OpenIDConnect#obtainuserinfo
	Issuer string `json:"iss"`

	// The client ID, or set of client IDs, that this token is issued for. For
	// common uses, this is the client that initialized the auth flow.
	Audience Audience `json:"aud"`

	// A unique string which identifies the end user.
	Subject string `json:"sub"`

	// Expiry of the token.
	Expiry NumericDate `json:"exp"`

	// When the token was issued by the provider.
	IssuedAt NumericDate `json:"iat"`

	// Initial nonce provided during the authentication redirect.
	//
	// If present, this package ensures this is a valid nonce.
	Nonce string `json:"nonce"`
	// contains filtered or unexported fields
}

NewIDToken is an OpenID Connect extension that provides a predictable representation of an authorization event.

The ID Token only holds fields OpenID Connect requires. To access additional claims returned by the server, use the Claims method.

func (*IDToken) Claims

func (i *IDToken) Claims(v interface{}) error

Claims unmarshals the raw JSON payload of the ID Token into a provided struct.

idToken, err := idTokenVerifier.Verify(rawIDToken)
if err != nil {
	// handle error
}
var claims struct {
	Email         string `json:"email"`
	EmailVerified bool   `json:"email_verified"`
}
if err := idToken.Claims(&claims); err != nil {
	// handle error
}

type IDTokenVerifier

type IDTokenVerifier struct {
	// contains filtered or unexported fields
}

IDTokenVerifier provides verification for ID Tokens.

func (*IDTokenVerifier) Verify

func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDToken, error)

Verify parses a raw ID Token, verifies it's been signed by the provider, preforms any additional checks depending on the Config, and returns the payload.

See: https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation

oidcToken, err := client.Exchange(ctx, r.URL.Query().Get("code"))
if err != nil {
    // handle error
}

token, err := verifier.Verify(ctx, oidcToken.IDToken)

type NumericDate

type NumericDate int64

NumericDate represents date and time as the number of seconds since the epoch, including leap seconds. Non-integer values can be represented in the serialized format, but we round to the nearest second.

func NewNumericDate

func NewNumericDate(t time.Time) NumericDate

NewNumericDate constructs NumericDate from time.Time value.

func (NumericDate) MarshalJSON

func (n NumericDate) MarshalJSON() ([]byte, error)

MarshalJSON serializes the given NumericDate into its JSON representation.

func (NumericDate) Time

func (n NumericDate) Time() time.Time

Time returns time.Time representation of NumericDate.

func (*NumericDate) UnmarshalJSON

func (n *NumericDate) UnmarshalJSON(b []byte) error

UnmarshalJSON reads a date from its JSON representation.

type ReuseTokenSource

type ReuseTokenSource struct {
	// contains filtered or unexported fields
}

ReuseTokenSource is a oidc TokenSource that holds a single token in memory and validates its expiry before each call to retrieve it with Token. If it's expired, it will be auto-refreshed using the new TokenSource.

func (*ReuseTokenSource) OIDCToken

func (s *ReuseTokenSource) OIDCToken(ctx context.Context) (*Token, error)

OIDCToken returns the current token if it's still valid, else will refresh the current token (using r.Context for HTTP client information) and return the new one.

func (*ReuseTokenSource) Verifier

func (s *ReuseTokenSource) Verifier() Verifier

Verifier returns verifier from underlying token source.

type Token

type Token struct {
	// AccessToken is the token that authorizes and authenticates
	// the requests. It can be used for API access or token revocation.
	AccessToken string `json:"access_token"`

	// AccessTokenExpiry is time when access token will be invalid.
	AccessTokenExpiry time.Time `json:"expiry"`

	// RefreshToken is used to refresh the access token and ID token if they expire.
	RefreshToken string `json:"refresh_token,omitempty"`

	// NewIDToken is a security token that contains Claims about the Authentication of an End-User by an Authorization
	// Server when using a Client, and potentially other requested Claims that helps in authorization itself.
	// The ID Token is always represented as a JWT.
	IDToken string `json:"id_token"`
}

Token is an Open ID Connect token's response described here: http://openid.net/specs/openid-connect-core-1_0.html#TokenResponse. Token is always Bearer type. See TokenResponse for full oauth2-compatible response.

func (Token) Claims

func (t Token) Claims(ctx context.Context, verifier Verifier, v interface{}) error

Claims unmarshals the raw JSON payload of the NewIDToken into a provided struct.

var claims struct {
	Email         string `json:"email"`
	EmailVerified bool   `json:"email_verified"`
}
if err := oidc.Token{NewIDToken: "<id token>"}.Claims(idTokenVerifier, &claims); err != nil {
	// handle error
}

func (*Token) IsAccessTokenExpired

func (t *Token) IsAccessTokenExpired() bool

IsAccessTokenExpired returns true if access token expired.

func (*Token) IsValid

func (t *Token) IsValid(ctx context.Context, verifier Verifier) error

IsValid validates oidc token by validating AccessToken and ID Token. If error is nil, the token is valid.

func (*Token) SetAuthHeader

func (t *Token) SetAuthHeader(r *http.Request)

SetAuthHeader sets the Authorization header to r using the access token in t.

type TokenRefresher

type TokenRefresher struct {
	// contains filtered or unexported fields
}

TokenRefresher is a TokenSource that makes "grant_type"=="refresh_token" HTTP requests to renew a token using a RefreshToken.

func (*TokenRefresher) OIDCToken

func (tf *TokenRefresher) OIDCToken(ctx context.Context) (*Token, error)

OIDCToken is not safe for concurrent access, as it updates the tokenRefresher's refreshToken field. It is meant to be used with ReuseTokenSource which synchronizes calls to this method with its own mutex. NOTE: Returned token is not verified.

func (*TokenRefresher) Verifier

func (tf *TokenRefresher) Verifier() Verifier

Verifier returns verifier for ID Token.

type TokenResponse

type TokenResponse struct {
	AccessToken string `json:"access_token"`
	TokenType   string `json:"token_type"`
	IDToken     string `json:"id_token"`

	ExpiresIn    expirationTime `json:"expires_in,omitempty"` // at least PayPal returns string, while most return number
	RefreshToken string         `json:"refresh_token,omitempty"`
	Scope        string         `json:"scope,omitempty"`
	// contains filtered or unexported fields
}

TokenResponse is the struct representing the HTTP response from OIDC providers returning a token in JSON form.

func (*TokenResponse) SetExpiry

func (r *TokenResponse) SetExpiry(expiry time.Time)

SetExpiry sets expiry in form of time in future.

type TokenSource

type TokenSource interface {
	// OIDCToken must be safe for concurrent use by multiple goroutines.
	// The returned Token must not be modified.
	OIDCToken(context.Context) (*Token, error)
	Verifier() Verifier
}

TokenSource is anything that can return an oidc token and verifier for token verification.

func NewReuseTokenSource

func NewReuseTokenSource(t *Token, src TokenSource) (ret TokenSource, clearIDToken func())

NewReuseTokenSource returns a TokenSource which repeatedly returns the same token as long as it's valid, starting with t. As a second argument it returns reset function that enables to reset h When its cached token is invalid, a new token is obtained from source.

func NewReuseTokenSourceWithDebugLogger

func NewReuseTokenSourceWithDebugLogger(debugLogger *log.Logger, t *Token, src TokenSource) (ret TokenSource, clearIDToken func())

NewReuseTokenSourceWithDebugLogger is the same as NewReuseTokenSource but with logger.

func NewTokenRefresher

func NewTokenRefresher(client *Client, cfg Config, refreshToken string) TokenSource

NewTokenRefresher constructs token refresher.

func StaticTokenSource

func StaticTokenSource(t *Token) TokenSource

StaticTokenSource returns a TokenSource that always returns the same token. Because the provided token t is never refreshed, StaticTokenSource is only useful for tokens that never expire.

type UserInfo

type UserInfo struct {
	Subject       string `json:"sub"`
	Profile       string `json:"profile"`
	Email         string `json:"email"`
	EmailVerified bool   `json:"email_verified"`
	// contains filtered or unexported fields
}

UserInfo represents the OpenID Connect userinfo claims.

func (*UserInfo) Claims

func (u *UserInfo) Claims(v interface{}) error

Claims unmarshals the raw JSON object claims into the provided object.

type VerificationConfig

type VerificationConfig struct {
	// Expected Audience of the token. For a majority of the cases this is expected to be
	// the ID of the client that initialized the login flow. It may occasionally differ if
	// the provider supports the authorizing party (azp) claim.
	//
	// If not provided, users must explicitly set SkipClientIDCheck.
	ClientID string

	// ClaimNonce for Verification.
	ClaimNonce string

	// If specified, only this set of algorithms may be used to sign the JWT.
	//
	// Since many providers only support RS256, SupportedSigningAlgs defaults to this value.
	SupportedSigningAlgs []string

	// Time function to check Token expiry. Defaults to time.Now
	Now func() time.Time
}

VerificationConfig is the configuration for an IDTokenVerifier.

type Verifier

type Verifier interface {
	Verify(ctx context.Context, rawIDToken string) (*IDToken, error)
}

Verifier is anything that can verify token and returned parsed standard oidc.NewIDToken. For example oidc.IDTokenVerifier.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL