func (o *Oauth2) Revoke(ctx context.Context, req *oauth2.RevokeRequest, rsp *oauth2.RevokeResponse) error { // Who should be allowed to do this? if len(req.RefreshToken) > 0 { token, _, err := db.ReadRefresh(req.RefreshToken) if err != nil { if err == db.ErrNotFound { return errors.BadRequest("go.micro.srv.auth", "invalid_request") } return errors.InternalServerError("go.micro.srv.auth", "server_error") } if err := db.DeleteToken(req.AccessToken); err != nil { return errors.InternalServerError("go.micro.srv.auth", "server_error") } req.AccessToken = token.AccessToken } if len(req.AccessToken) == 0 { return errors.BadRequest("go.micro.srv.auth", "invalid_request") } if err := db.DeleteToken(req.AccessToken); err != nil { return errors.InternalServerError("go.micro.srv.auth", "server_error") } return nil }
func (o *Oauth2) Token(ctx context.Context, req *oauth2.TokenRequest, rsp *oauth2.TokenResponse) error { // We may actually need to authenticate who can make this request. // How should we do that? // TODO: track multiple attempts for the same authorization code and revoke all other tokens // supported grant types switch req.GrantType { case "authorization_code": // validate inputs if len(req.Code) == 0 || len(req.ClientId) == 0 || len(req.ClientSecret) == 0 { return errors.BadRequest("go.micro.srv.auth", "invalid_request") } // read authorization request storedReq, err := db.ReadRequest(req.Code) if err != nil { if err == db.ErrNotFound { return errors.BadRequest("go.micro.srv.auth", "invalid_request") } else { return errors.InternalServerError("go.micro.srv.auth", "server_error") } } // we have a request, is it the same client_id? if req.ClientId != storedReq.ClientId { return errors.BadRequest("go.micro.srv.auth", "invalid_request") } // is it the same redirect uri? if req.RedirectUri != storedReq.RedirectUri { return errors.BadRequest("go.micro.srv.auth", "invalid_request") } // auth if err := authClient(req.ClientId, req.ClientSecret); err != nil { return err } // ok successful auth // generate a token; tokens are basically opaque strings // we just hand back something random and base64 encoded token := &oauth2.Token{ AccessToken: db.Token(), TokenType: "bearer", RefreshToken: db.Token(), ExpiresAt: time.Now().Add(time.Hour).Unix(), Scopes: storedReq.Scopes, Metadata: req.Metadata, } // store the token against the client if err := db.CreateToken(token, req.ClientId, req.Code); err != nil { return errors.InternalServerError("go.micro.srv.auth", "server_error") } // return token rsp.Token = token case "client_credentials": // validate inputs if len(req.ClientId) == 0 || len(req.ClientSecret) == 0 { return errors.BadRequest("go.micro.srv.auth", "invalid_request") } // auth if err := authClient(req.ClientId, req.ClientSecret); err != nil { return err } // ok successful auth // generate a token; tokens are basically opaque strings // we just hand back something random and base64 encoded token := &oauth2.Token{ AccessToken: db.Token(), TokenType: "bearer", RefreshToken: db.Token(), ExpiresAt: time.Now().Add(time.Hour).Unix(), Scopes: req.Scopes, Metadata: req.Metadata, } // store the token against the client if err := db.CreateToken(token, req.ClientId, ""); err != nil { return errors.InternalServerError("go.micro.srv.auth", "server_error") } // return token rsp.Token = token case "refresh_token": // validate inputs if len(req.RefreshToken) == 0 || len(req.ClientId) == 0 || len(req.ClientSecret) == 0 { return errors.BadRequest("go.micro.srv.auth", "invalid_request") } // auth client if err := authClient(req.ClientId, req.ClientSecret); err != nil { return err } // get existing token token, clientId, err := db.ReadRefresh(req.RefreshToken) if err != nil { if err == db.ErrNotFound { return errors.BadRequest("go.micro.srv.auth", "invalid_request") } return errors.InternalServerError("go.micro.srv.auth", "server_error") } // client id does not match for refresh token if clientId != req.ClientId { return errors.BadRequest("go.micro.srv.auth", "access_denied") } // so we have a token, we now need to refresh id := token.AccessToken token.AccessToken = db.Token() token.RefreshToken = db.Token() token.ExpiresAt = time.Now().Add(time.Hour).Unix() // Update with new access token, refresh token and expiry // refresh expiry is set by db if err := db.UpdateToken(id, token); err != nil { return errors.InternalServerError("go.micro.srv.auth", "server_error") } rsp.Token = token default: return errors.BadRequest("go.micro.srv.auth", "unsupported_grant_type") } // Delete the authorization request when we successfully create a token if err := db.DeleteRequest(req.Code); err != nil { return errors.InternalServerError("go.micro.srv.auth", "server_error") } return nil }